]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- postgres no longer uses client-side cursors, uses more efficient server side
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 10 Jan 2007 07:49:37 +0000 (07:49 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 10 Jan 2007 07:49:37 +0000 (07:49 +0000)
  cursors via apparently undocumented psycopg2 behavior recently discovered on the
  mailing list.  disable it via create_engine('postgres://', client_side_cursors=True)

CHANGES
lib/sqlalchemy/databases/postgres.py
lib/sqlalchemy/engine/base.py
lib/sqlalchemy/engine/default.py

diff --git a/CHANGES b/CHANGES
index a7f3d2e047471a361c155d7fe0d616d3c3e0e307..99d1316fad6edbeb813cccf1e17e85ae7aadd48e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,9 @@
   completely illiterate, but its definitely sub-optimal to "ensure" which is
   non-ambiguous.
 - sql:
+  - postgres no longer uses client-side cursors, uses more efficient server side 
+  cursors via apparently undocumented psycopg2 behavior recently discovered on the 
+  mailing list.  disable it via create_engine('postgres://', client_side_cursors=True)
   - added "BIGSERIAL" support for postgres table with PGBigInteger/autoincrement
   - fixes to postgres reflection to better handle when schema names are present;
   thanks to jason (at) ncsmags.com [ticket:402]
index a7dc29e9f69b3c616eeb824abf15501338e992fd..79db8716c3601490662d91234b81b2af85065e44 100644 (file)
@@ -191,7 +191,6 @@ def descriptor():
     ]}
 
 class PGExecutionContext(default.DefaultExecutionContext):
-
     def post_exec(self, engine, proxy, compiled, parameters, **kwargs):
         if getattr(compiled, "isinsert", False) and self.last_inserted_ids is None:
             if not engine.dialect.use_oids:
@@ -208,8 +207,9 @@ class PGExecutionContext(default.DefaultExecutionContext):
                 self._last_inserted_ids = [v for v in row]
     
 class PGDialect(ansisql.ANSIDialect):
-    def __init__(self, module=None, use_oids=False, use_information_schema=False, **params):
+    def __init__(self, module=None, use_oids=False, use_information_schema=False, client_side_cursors=False, **params):
         self.use_oids = use_oids
+        self.client_side_cursors = client_side_cursors
         if module is None:
             #if psycopg is None:
             #    raise exceptions.ArgumentError("Couldnt locate psycopg1 or psycopg2: specify postgres module argument")
@@ -240,6 +240,15 @@ class PGDialect(ansisql.ANSIDialect):
         opts.update(url.query)
         return ([], opts)
 
+    def create_cursor(self, connection):
+        if self.client_side_cursors:
+            return connection.cursor()
+        else:
+            # use server-side cursors:
+            # http://lists.initd.org/pipermail/psycopg/2007-January/005251.html
+            return connection.cursor('x')
+
+
     def create_execution_context(self):
         return PGExecutionContext(self)
 
@@ -248,7 +257,7 @@ class PGDialect(ansisql.ANSIDialect):
             return sqltypes.adapt_type(typeobj, pg2_colspecs)
         else:
             return sqltypes.adapt_type(typeobj, pg1_colspecs)
-
+        
     def compiler(self, statement, bindparams, **kwargs):
         return PGCompiler(self, statement, bindparams, **kwargs)
     def schemagenerator(self, *args, **kwargs):
index e696950b9513735f2830e9f587174502eb0ab00f..7fcf52af6d7161b8a7373481e54ddb92a034dbb6 100644 (file)
@@ -113,6 +113,9 @@ class Dialect(sql.AbstractDialect):
         raise NotImplementedError()
     def do_execute(self, cursor, statement, parameters):
         raise NotImplementedError()
+    def create_cursor(self, connection):
+        """return a new cursor generated from the given connection"""
+        raise NotImplementedError()
     def compile(self, clauseelement, parameters=None):
         """compile the given ClauseElement using this Dialect.
         
@@ -279,7 +282,7 @@ class Connection(Connectable):
         return self.execute_compiled(elem.compile(engine=self.__engine, parameters=param), *multiparams, **params)
     def execute_compiled(self, compiled, *multiparams, **params):
         """executes a sql.Compiled object."""
-        cursor = self.connection.cursor()
+        cursor = self.__engine.dialect.create_cursor(self.connection)
         parameters = [compiled.get_params(**m) for m in self._params_to_listofdicts(*multiparams, **params)]
         if len(parameters) == 1:
             parameters = parameters[0]
@@ -319,7 +322,7 @@ class Connection(Connectable):
         return callable_(self)
     def _execute_raw(self, statement, parameters=None, cursor=None, context=None, **kwargs):
         if cursor is None:
-            cursor = self.connection.cursor()
+            cursor = self.__engine.dialect.create_cursor(self.connection)
         try:
             self.__engine.logger.info(statement)
             self.__engine.logger.info(repr(parameters))
index bc39b9b8a69e258dad6e2cf9c15fd5c968e81fc4..94c01f324909807fcffe35605bb726730efd2bdb 100644 (file)
@@ -64,6 +64,8 @@ class DefaultDialect(base.Dialect):
         cursor.execute(statement, parameters)
     def defaultrunner(self, engine, proxy):
         return base.DefaultRunner(engine, proxy)
+    def create_cursor(self, connection):
+        return connection.cursor()
         
     def _set_paramstyle(self, style):
         self._paramstyle = style