--- sqlalchemy/lib/sqlalchemy/databases/postgres.py	2007/03/13 11:30:43
+++ sqlalchemy/lib/sqlalchemy/databases/postgres.py	2007/03/23 09:45:06
@@ -4,7 +4,7 @@
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-import datetime, sys, StringIO, string, types, re
+import datetime, sys, StringIO, string, types, re, time, hashlib
 
 import sqlalchemy.util as util
 import sqlalchemy.sql as sql
@@ -238,6 +238,7 @@
         # produce consistent paramstyle even if psycopg2 module not present
         if self.module is None:
             self.paramstyle = 'pyformat'
+        self.__txn_ids = {}
         
     def create_connect_args(self, url):
         opts = url.translate_connect_args(['host', 'database', 'user', 'password', 'port'])
@@ -294,6 +295,32 @@
         else:
             return None
 
+    def do_prepare(self, connection):
+        if connection in self.__txn_ids:
+            raise exceptions.InvalidRequestError("Transaction already prepared for this connection")
+        h = hashlib.md5()
+        h.update(str(id(connection)))
+        h.update(str(time.time()))
+        txn_id = h.hexdigest()
+        self.__txn_ids[connection] = txn_id
+        connection.cursor().execute("PREPARE TRANSACTION '%s'" % txn_id)
+    
+    def do_rollback(self, connection):
+        if connection not in self.__txn_ids:
+            super(PGDialect, self).do_rollback(connection)
+        else:
+            connection.cursor().execute("ROLLBACK PREPARED '%s'" % \
+                                        self.__txn_ids[connection])
+            del self.__txn_ids[connection]
+    
+    def do_commit(self, connection):
+        if connection not in self.__txn_ids:
+            super(PGDialect, self).do_commit(connection)
+        else:
+            connection.cursor().execute("COMMIT PREPARED '%s'" % \
+                                        self.__txn_ids[connection])
+            del self.__txn_ids[connection]
+    
     def do_executemany(self, c, statement, parameters, context=None):
         """we need accurate rowcounts for updates, inserts and deletes.  psycopg2 is not nice enough
         to produce this correctly for an executemany, so we do our own executemany here."""
--- sqlalchemy/lib/sqlalchemy/engine/base.py	2007/03/13 11:30:43
+++ sqlalchemy/lib/sqlalchemy/engine/base.py	2007/03/23 09:51:57
@@ -108,6 +108,9 @@
     def do_begin(self, connection):
         """provides an implementation of connection.begin()"""
         raise NotImplementedError()
+    def do_prepare(self, connection):
+        """provides an implementation of 'PREPARE TRANSACTION'"""
+        raise NotImplementedError()
     def do_rollback(self, connection):
         """provides an implementation of connection.rollback()"""
         raise NotImplementedError()
@@ -234,6 +237,9 @@
     def _begin_impl(self):
         self.__engine.logger.info("BEGIN")
         self.__engine.dialect.do_begin(self.connection)
+    def _prepare_impl(self):
+        self.__engine.logger.info("PREPARE")
+        self.__engine.dialect.do_prepare(self.connection)
     def _rollback_impl(self):
         self.__engine.logger.info("ROLLBACK")
         self.__engine.dialect.do_rollback(self.connection)
@@ -397,6 +403,11 @@
             self.__connection._begin_impl()
     connection = property(lambda s:s.__connection, doc="The Connection object referenced by this Transaction")
     is_active = property(lambda s:s.__is_active)
+    def prepare(self):
+        if not self.__parent.__is_active:
+            raise exceptions.InvalidRequestError("This transaction is inactive")
+        if self.__parent is self:
+            self.__connection._prepare_impl()
     def rollback(self):
         if not self.__parent.__is_active:
             return
--- sqlalchemy/lib/sqlalchemy/engine/default.py	2007/03/13 11:30:43
+++ sqlalchemy/lib/sqlalchemy/engine/default.py	2007/03/23 09:45:06
@@ -48,6 +48,9 @@
         """implementations might want to put logic here for turning autocommit on/off,
         etc."""
         pass
+    def do_prepare(self, connection):
+        """implementations might want to put logic here for preparing transactions"""
+        pass
     def do_rollback(self, connection):
         """implementations might want to put logic here for turning autocommit on/off,
         etc."""
--- sqlalchemy/lib/sqlalchemy/orm/session.py	2007/03/13 11:30:43
+++ sqlalchemy/lib/sqlalchemy/orm/session.py	2007/03/23 09:45:06
@@ -53,6 +53,8 @@
         if self.autoflush:
             self.session.flush()
         for t in self.connections.values():
+            t[1].prepare()
+        for t in self.connections.values():
             t[1].commit()
         self.close()
     def rollback(self):
