mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-14 20:57:19 -04:00
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.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
+19
-4
@@ -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)
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+5
-5
@@ -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 <sqlite|sqlite_file|postgres|mysql|oracle> 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):
|
||||
|
||||
Reference in New Issue
Block a user