From: Mike Bayer Date: Wed, 10 Jan 2007 07:49:37 +0000 (+0000) Subject: - postgres no longer uses client-side cursors, uses more efficient server side X-Git-Tag: rel_0_3_4~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba3ebe44dec08fa74363d63a19ddc2b2782f3350;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - 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) --- diff --git a/CHANGES b/CHANGES index a7f3d2e047..99d1316fad 100644 --- 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] diff --git a/lib/sqlalchemy/databases/postgres.py b/lib/sqlalchemy/databases/postgres.py index a7dc29e9f6..79db8716c3 100644 --- a/lib/sqlalchemy/databases/postgres.py +++ b/lib/sqlalchemy/databases/postgres.py @@ -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): diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index e696950b95..7fcf52af6d 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -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)) diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index bc39b9b8a6..94c01f3249 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -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