summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-10-16 16:03:59 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-10-16 16:03:59 +0000
commit9b22fc0a9b5a6e97129096dd5ee8b3eb24895ac4 (patch)
tree798ca0b3fdffe8c045e50e09793ffbfc0adb032e /lib/sqlalchemy
parent9226871456014f1283633ead19fac23487a0e429 (diff)
downloadsqlalchemy-9b22fc0a9b5a6e97129096dd5ee8b3eb24895ac4.tar.gz
- Fixed SQL compiler's awareness of top-level column labels as used
in result-set processing; nested selects which contain the same column names don't affect the result or conflict with result-column metadata. - query.get() and related functions (like many-to-one lazyloading) use compile-time-aliased bind parameter names, to prevent name conflicts with bind parameters that already exist in the mapped selectable.
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/mapper.py7
-rw-r--r--lib/sqlalchemy/orm/query.py5
-rw-r--r--lib/sqlalchemy/orm/strategies.py6
-rw-r--r--lib/sqlalchemy/sql/compiler.py4
4 files changed, 13 insertions, 9 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 5e20cf6b6..b68b4c8fe 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -464,9 +464,12 @@ class Mapper(object):
self.__log("Identified primary key columns: " + str(primary_key))
_get_clause = sql.and_()
+ _get_params = {}
for primary_key in self.primary_key:
- _get_clause.clauses.append(primary_key == sql.bindparam(primary_key._label, type_=primary_key.type, unique=True))
- self._get_clause = _get_clause
+ bind = sql.bindparam(None, type_=primary_key.type)
+ _get_params[primary_key] = bind
+ _get_clause.clauses.append(primary_key == bind)
+ self._get_clause = (_get_clause, _get_params)
def _get_equivalent_columns(self):
"""Create a map of all *equivalent* columns, based on
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 0d04b768c..f6268579f 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -708,16 +708,17 @@ class Query(object):
ident = util.to_list(ident)
params = {}
+ (_get_clause, _get_params) = self.select_mapper._get_clause
for i, primary_key in enumerate(self.primary_key_columns):
try:
- params[primary_key._label] = ident[i]
+ params[_get_params[primary_key].key] = ident[i]
except IndexError:
raise exceptions.InvalidRequestError("Could not find enough values to formulate primary key for query.get(); primary key columns are %s" % ', '.join(["'%s'" % str(c) for c in self.primary_key_columns]))
try:
q = self
if lockmode is not None:
q = q.with_lockmode(lockmode)
- q = q.filter(self.select_mapper._get_clause)
+ q = q.filter(_get_clause)
q = q.params(params)._select_context_options(populate_existing=reload, version_check=(lockmode is not None))
# call using all() to avoid LIMIT compilation complexity
return q.all()[0]
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 5725b5f8e..716a6dbba 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -200,11 +200,11 @@ class DeferredColumnLoader(LoaderStrategy):
raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))
if create_statement is None:
- clause = localparent._get_clause
+ (clause, param_map) = localparent._get_clause
ident = instance._instance_key[1]
params = {}
for i, primary_key in enumerate(localparent.primary_key):
- params[primary_key._label] = ident[i]
+ params[param_map[primary_key].key] = ident[i]
statement = sql.select([p.columns[0] for p in group], clause, from_obj=[localparent.mapped_table], use_labels=True)
else:
statement, params = create_statement()
@@ -294,7 +294,7 @@ class LazyLoader(AbstractRelationLoader):
# determine if our "lazywhere" clause is the same as the mapper's
# get() clause. then we can just use mapper.get()
#from sqlalchemy.orm import query
- self.use_get = not self.uselist and self.mapper._get_clause.compare(self.lazywhere)
+ self.use_get = not self.uselist and self.mapper._get_clause[0].compare(self.lazywhere)
if self.use_get:
self.logger.info(str(self.parent_property) + " will use query.get() to optimize instance loads")
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 05c7a5cf4..5572c2ed4 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -240,7 +240,7 @@ class DefaultCompiler(engine.Compiled, visitors.ClauseVisitor):
def visit_label(self, label):
labelname = self._truncated_identifier("colident", label.name)
- if self.stack and self.stack[-1].get('select'):
+ if len(self.stack) == 1 and self.stack[-1].get('select'):
self.typemap.setdefault(labelname.lower(), label.obj.type)
if isinstance(label.obj, sql._ColumnClause):
self.column_labels[label.obj._label] = labelname
@@ -258,7 +258,7 @@ class DefaultCompiler(engine.Compiled, visitors.ClauseVisitor):
else:
name = column.name
- if self.stack and self.stack[-1].get('select'):
+ if len(self.stack) == 1 and self.stack[-1].get('select'):
# if we are within a visit to a Select, set up the "typemap"
# for this column which is used to translate result set values
self.typemap.setdefault(name.lower(), column.type)