Index: lib/sqlalchemy/databases/postgres.py
===================================================================
--- lib/sqlalchemy/databases/postgres.py	(revision 2427)
+++ lib/sqlalchemy/databases/postgres.py	(working copy)
@@ -490,6 +490,12 @@
 
                 table.append_constraint(ForeignKeyConstraint(constrained_columns, refspec, conname))
 
+    def create_result_proxy_args(self, connection, cursor):
+        args = super(PGDialect, self).create_result_proxy_args(connection, cursor)
+        if self.server_side_cursors:
+            args['delay_metadata'] = True
+        return args
+
 class PGCompiler(ansisql.ANSICompiler):
     def visit_insert_column(self, column, parameters):
         # all column primary key inserts must be explicitly present
Index: lib/sqlalchemy/engine/base.py
===================================================================
--- lib/sqlalchemy/engine/base.py	(revision 2427)
+++ lib/sqlalchemy/engine/base.py	(working copy)
@@ -800,10 +800,12 @@
     def __new__(cls, *args, **kwargs):
         if cls is ResultProxy and kwargs.has_key('should_prefetch') and kwargs['should_prefetch']:
             return PrefetchingResultProxy(*args, **kwargs)
+        elif cls is ResultProxy and kwargs.has_key('delay_metadata') and kwargs['delay_metadata']:
+            return DelayedMetaResultProxy(*args, **kwargs)
         else:
             return object.__new__(cls, *args, **kwargs)
 
-    def __init__(self, engine, connection, cursor, executioncontext=None, typemap=None, columns=None, should_prefetch=None):
+    def __init__(self, engine, connection, cursor, executioncontext=None, typemap=None, columns=None, should_prefetch=None, delay_metadata=None):
         """ResultProxy objects are constructed via the execute() method on SQLEngine."""
 
         self.connection = connection
@@ -819,16 +821,20 @@
             self.rowcount = cursor.rowcount
         self.__key_cache = {}
         self.__echo = engine.echo == 'debug'
-        metadata = cursor.description
         self.props = {}
         self.keys = []
-        i = 0
+        self.typemap = typemap
+
+        if not delay_metadata:
+            self._load_metadata(cursor.description)
+
+    def _load_metadata(self, metadata):
         if metadata is not None:
-            for item in metadata:
+            for i, item in enumerate(metadata):
                 # sqlite possibly prepending table name to colnames so strip
                 colname = item[0].split('.')[-1].lower()
-                if typemap is not None:
-                    rec = (typemap.get(colname, types.NULLTYPE), i)
+                if self.typemap is not None:
+                    rec = (self.typemap.get(colname, types.NULLTYPE), i)
                 else:
                     rec = (types.NULLTYPE, i)
                 if rec[0] is None:
@@ -837,7 +843,6 @@
                     self.props[colname] = (ResultProxy.AmbiguousColumn(colname), 0)
                 self.keys.append(colname)
                 self.props[i] = rec
-                i+=1
 
     def _executioncontext(self):
         try:
@@ -1009,6 +1014,64 @@
         finally:
             self.close()
 
+class DelayedMetaResultProxy(ResultProxy):
+    def fetchall(self):
+        """Fetch all rows, just like DBAPI ``cursor.fetchall()``."""
+
+        l = []
+        for row in self.cursor.fetchall():
+            l.append(RowProxy(self, row))
+        if not self.props:
+            self._load_metadata(self.cursor.description)
+        self.close()
+        return l
+
+    def fetchmany(self, size=None):
+        """Fetch many rows, just like DBAPI ``cursor.fetchmany(size=cursor.arraysize)``."""
+
+        if size is None:
+            rows = self.cursor.fetchmany()
+        else:
+            rows = self.cursor.fetchmany(size=size)
+        l = []
+        for row in rows:
+            l.append(RowProxy(self, row))
+            
+        #replace fetchmany with super's after first call
+        if not self.props:
+            self._load_metadata(self.cursor.description)
+            self.fetchmany = super(DelayedMetaResultProxy, self).fetchmany
+
+        if len(l) == 0:
+            self.close()
+        return l
+
+    def fetchone(self):
+        """fetch one row, just like DBAPI cursor.fetchone()."""
+        super_fn = super(DelayedMetaResultProxy, self).fetchone
+        res = super_fn()
+        
+        #replace fetchone with super's after first call
+        if not self.props:
+            self._load_metadata(self.cursor.description)
+            self.fetchone = super_fn
+        return res
+
+    def scalar(self):
+        """Fetch the first column of the first row, and close the result set."""
+
+        row = self.cursor.fetchone()
+        try:
+            if not self.props:
+                self._load_metadata(self.cursor.description)
+            if row is not None:
+                return RowProxy(self, row)[0]
+            else:
+                return None
+        finally:
+            self.close()
+
+
 class PrefetchingResultProxy(ResultProxy):
     """ResultProxy that loads all columns into memory each time fetchone() is
     called.  If fetchmany() or fetchall() are called, the full grid of results
