From: Mike Bayer Date: Sun, 1 Jan 2006 21:08:22 +0000 (+0000) Subject: rowid_column becomes more like the "order by column". 'default_ordering' flag sent... X-Git-Tag: rel_0_1_0~186 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=705f308452b0741747c27ee4edcd75f2ec0e6ae8;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git rowid_column becomes more like the "order by column". 'default_ordering' flag sent to create_engine enables whether or not the rowid_column on a Table will be None or not. mappers/relations will by default use the rowid_column for ordering if its not None, else theres no default ordering. still should better define 'default_ordering'/'rowid_column' relationship since its a little kludgy. --- diff --git a/lib/sqlalchemy/databases/postgres.py b/lib/sqlalchemy/databases/postgres.py index 3ae83cb8c4..e00d16d048 100644 --- a/lib/sqlalchemy/databases/postgres.py +++ b/lib/sqlalchemy/databases/postgres.py @@ -106,7 +106,8 @@ def descriptor(): ]} class PGSQLEngine(ansisql.ANSISQLEngine): - def __init__(self, opts, module = None, **params): + def __init__(self, opts, module=None, use_oids=False, **params): + self.use_oids = use_oids if module is None: if psycopg is None: raise "Couldnt locate psycopg1 or psycopg2: specify postgres module argument" @@ -153,20 +154,28 @@ class PGSQLEngine(ansisql.ANSISQLEngine): def last_inserted_ids(self): return self.context.last_inserted_ids + def rowid_column_name(self): + if self.use_oids: + return "oid" + else: + return None + def pre_exec(self, proxy, statement, parameters, **kwargs): return def post_exec(self, proxy, compiled, parameters, **kwargs): if getattr(compiled, "isinsert", False) and self.context.last_inserted_ids is None: - raise "cant use cursor.lastrowid without OIDs enabled" - table = compiled.statement.table - cursor = proxy() - if cursor.lastrowid is not None and table is not None and len(table.primary_key): - s = sql.select(table.primary_key, table.rowid_column == cursor.lastrowid) - c = s.compile() - cursor = proxy(str(c), c.get_params()) - row = cursor.fetchone() - self.context.last_inserted_ids = [v for v in row] + if not self.use_oids: + raise "cant use cursor.lastrowid without OIDs enabled" + else: + table = compiled.statement.table + cursor = proxy() + if cursor.lastrowid is not None and table is not None and len(table.primary_key): + s = sql.select(table.primary_key, table.rowid_column == cursor.lastrowid) + c = s.compile() + cursor = proxy(str(c), c.get_params()) + row = cursor.fetchone() + self.context.last_inserted_ids = [v for v in row] def _executemany(self, c, statement, parameters): """we need accurate rowcounts for updates, inserts and deletes. psycopg2 is not nice enough @@ -177,7 +186,6 @@ class PGSQLEngine(ansisql.ANSISQLEngine): rowcount += c.rowcount self.context.rowcount = rowcount - def dbapi(self): return self.module diff --git a/lib/sqlalchemy/engine.py b/lib/sqlalchemy/engine.py index f3cc8efada..68cf089315 100644 --- a/lib/sqlalchemy/engine.py +++ b/lib/sqlalchemy/engine.py @@ -161,7 +161,7 @@ class SQLEngine(schema.SchemaEngine): SQLEngines are constructed via the create_engine() function inside this package. """ - def __init__(self, pool = None, echo = False, logger = None, **params): + def __init__(self, pool=None, echo=False, logger=None, default_ordering=False, **params): """constructs a new SQLEngine. SQLEngines should be constructed via the create_engine() function which will construct the appropriate subclass of SQLEngine.""" # get a handle on the connection pool via the connect arguments @@ -172,6 +172,7 @@ class SQLEngine(schema.SchemaEngine): self._pool = sqlalchemy.pool.manage(self.dbapi(), **params).get_pool(*cargs, **cparams) else: self._pool = pool + self.default_ordering=default_ordering self.echo = echo self.context = util.ThreadLocal(raiseerror=False) self.tables = {} @@ -258,7 +259,7 @@ class SQLEngine(schema.SchemaEngine): raise NotImplementedError() def rowid_column_name(self): - """returns the ROWID column name for this engine.""" + """returns the ROWID column name for this engine, or None if the engine cant/wont support OID/ROWID.""" return "oid" def supports_sane_rowcount(self): diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py index f9b62b9f5a..6af044fbbd 100644 --- a/lib/sqlalchemy/mapping/mapper.py +++ b/lib/sqlalchemy/mapping/mapper.py @@ -603,7 +603,7 @@ class Mapper(object): if self.order_by: order_by = self.order_by elif self.table.rowid_column is not None: - order_by = self.table.rowid_column + order_by = [self.table.rowid_column] else: order_by = None else: @@ -611,7 +611,7 @@ class Mapper(object): if self._should_nest(**kwargs): s2 = sql.select(self.table.primary_key, whereclause, use_labels=True, **kwargs) - if not kwargs.get('distinct', False): + if not kwargs.get('distinct', False) and self.table.rowid_column is not None: s2.order_by(self.table.rowid_column) s3 = s2.alias('rowcount') crit = [] @@ -621,17 +621,17 @@ class Mapper(object): if kwargs.has_key('order_by'): statement.order_by(*kwargs['order_by']) else: - statement.order_by(order_by) + statement.order_by(*order_by) else: statement = sql.select([], whereclause, from_obj=[self.table], use_labels=True, **kwargs) if order_by is not None and kwargs.get('order_by', None) is None: - statement.order_by(order_by) + statement.order_by(*order_by) # for a DISTINCT query, you need the columns explicitly specified in order # to use it in "order_by" - in the case we added the rowid column in, # add that to the column list # TODO: this idea should be handled by the SELECT statement itself, insuring # that order_by cols are in the select list if DISTINCT is selected - if kwargs.get('distinct', False) and order_by is self.table.rowid_column: + if kwargs.get('distinct', False) and self.table.rowid_column is not None and order_by == [self.table.rowid_column]: statement.append_column(self.table.rowid_column) # plugin point diff --git a/lib/sqlalchemy/mapping/properties.py b/lib/sqlalchemy/mapping/properties.py index 6fb078d78e..d049aec988 100644 --- a/lib/sqlalchemy/mapping/properties.py +++ b/lib/sqlalchemy/mapping/properties.py @@ -592,7 +592,7 @@ class LazyLoader(PropertyLoader): if allparams: if self.order_by is not None: order_by = self.order_by - elif self.secondary is not None: + elif self.secondary is not None and self.secondary.rowid_column is not None: order_by = [self.secondary.rowid_column] else: order_by = None @@ -714,11 +714,11 @@ class EagerLoader(PropertyLoader): if self.secondaryjoin is not None: statement._outerjoin = sql.outerjoin(towrap, self.secondary, self.primaryjoin).outerjoin(self.eagertarget, self.eagersecondary) - if self.order_by is None: + if self.order_by is None and self.secondary.rowid_column is not None: statement.order_by(self.secondary.rowid_column) else: statement._outerjoin = towrap.outerjoin(self.eagertarget, self.eagerprimary) - if self.order_by is None: + if self.order_by is None and self.eagertarget.rowid_column is not None: statement.order_by(self.eagertarget.rowid_column) if self.eager_order_by is not None: diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index 79af19cc01..65246cdf22 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -904,10 +904,25 @@ class TableImpl(FromClause): def __init__(self, table): self.table = table self.id = self.table.name - self._rowid_column = schema.Column(self.table.engine.rowid_column_name(), sqltypes.Integer, hidden=True) - self._rowid_column._set_parent(table) - - rowid_column = property(lambda s: s._rowid_column) + + def _rowid_col(self): + if not self.table.engine.default_ordering: + return None + + if not hasattr(self, '_rowid_column'): + if self.table.engine.rowid_column_name() is not None: + self._rowid_column = schema.Column(self.table.engine.rowid_column_name(), sqltypes.Integer, hidden=True) + self._rowid_column._set_parent(self.table) + else: + if len(self.table.primary_key) > 0: + c = self.table.primary_key[0] + else: + c = self.table.columns[self.table.columns.keys()[0]] + self._rowid_column = schema.Column(c.name, c.type, hidden=True) + self._rowid_column._set_parent(self.table) + return self._rowid_column + + rowid_column = property(_rowid_col) engine = property(lambda s: s.table.engine) columns = property(lambda self: self.table.columns) diff --git a/test/mapper.py b/test/mapper.py index 95ab4cb664..2c5cfa7e20 100644 --- a/test/mapper.py +++ b/test/mapper.py @@ -625,7 +625,7 @@ class EagerTest(MapperSuperTest): items = orderitems m = mapper(Item, items, properties = dict( - keywords = relation(Keyword, keywords, itemkeywords, lazy = False), + keywords = relation(Keyword, keywords, itemkeywords, lazy=False), )) l = m.select() self.assert_result(l, Item, *item_keyword_result) diff --git a/test/testbase.py b/test/testbase.py index c1342a5fcb..825d540fa4 100644 --- a/test/testbase.py +++ b/test/testbase.py @@ -23,17 +23,17 @@ def parse_argv(): global db if DBTYPE == 'sqlite': try: - db = engine.create_engine('sqlite://filename=:memory:', echo = echo) + db = engine.create_engine('sqlite://filename=:memory:', echo=echo, default_ordering=True) except: raise "Could not create sqlite engine. specify --db to test runner." elif DBTYPE == 'sqlite_file': - db = engine.create_engine('sqlite://filename=querytest.db', echo = echo) + db = engine.create_engine('sqlite://filename=querytest.db', echo=echo, default_ordering=True) elif DBTYPE == 'postgres': - db = engine.create_engine('postgres://database=test&host=127.0.0.1&user=scott&password=tiger', echo=echo) + db = engine.create_engine('postgres://database=test&host=127.0.0.1&user=scott&password=tiger', echo=echo, default_ordering=True) elif DBTYPE == 'mysql': - db = engine.create_engine('mysql://db=test&host=127.0.0.1&user=scott&passwd=tiger', echo=echo) + db = engine.create_engine('mysql://db=test&host=127.0.0.1&user=scott&passwd=tiger', echo=echo, default_ordering=True) elif DBTYPE == 'oracle': - db = engine.create_engine('oracle://user=scott&password=tiger', echo=echo) + db = engine.create_engine('oracle://user=scott&password=tiger', echo=echo, default_ordering=True) db = EngineAssert(db) class PersistTest(unittest.TestCase):