summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-07-06 12:35:45 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2011-07-06 12:35:45 -0400
commit5b8738b7e390471bd31b9ece90d0a3fd7653d859 (patch)
tree81b520b5ef6dd004f61112441d8b0c5bd76270a5 /lib
parent138774b234457bde1af522062be74403d71ea7d9 (diff)
downloadsqlalchemy-5b8738b7e390471bd31b9ece90d0a3fd7653d859.tar.gz
- The join condition produced by with_parent
as well as when using a "dynamic" relationship against a parent will generate unique bindparams, rather than incorrectly repeating the same bindparam. [ticket:2207]. Also in 0.6.9.
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/strategies.py51
-rw-r--r--lib/sqlalchemy/sql/expression.py9
-rw-r--r--lib/sqlalchemy/sql/util.py6
3 files changed, 43 insertions, 23 deletions
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 221e9730e..2adc5733a 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -323,18 +323,24 @@ class LazyLoader(AbstractRelationshipLoader):
def init(self):
super(LazyLoader, self).init()
- self.__lazywhere, \
- self.__bind_to_col, \
+ self._lazywhere, \
+ self._bind_to_col, \
self._equated_columns = self._create_lazy_clause(self.parent_property)
- self.logger.info("%s lazy loading clause %s", self, self.__lazywhere)
+ self._rev_lazywhere, \
+ self._rev_bind_to_col, \
+ self._rev_equated_columns = self._create_lazy_clause(
+ self.parent_property,
+ reverse_direction=True)
+
+ self.logger.info("%s lazy loading clause %s", self, self._lazywhere)
# 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[0].compare(
- self.__lazywhere,
+ self._lazywhere,
use_proxies=True,
equivalents=self.mapper._equivalent_columns
)
@@ -381,14 +387,14 @@ class LazyLoader(AbstractRelationshipLoader):
if not reverse_direction:
criterion, bind_to_col, rev = \
- self.__lazywhere, \
- self.__bind_to_col, \
+ self._lazywhere, \
+ self._bind_to_col, \
self._equated_columns
else:
criterion, bind_to_col, rev = \
- LazyLoader._create_lazy_clause(
- self.parent_property,
- reverse_direction=reverse_direction)
+ self._rev_lazywhere, \
+ self._rev_bind_to_col, \
+ self._rev_equated_columns
if reverse_direction:
mapper = self.parent_property.mapper
@@ -404,15 +410,18 @@ class LazyLoader(AbstractRelationshipLoader):
sess = sessionlib._state_session(state)
if sess is not None and sess._flushing:
def visit_bindparam(bindparam):
- if bindparam.key in bind_to_col:
+ if bindparam._identifying_key in bind_to_col:
bindparam.callable = \
- lambda: mapper._get_committed_state_attr_by_column(
- state, dict_, bind_to_col[bindparam.key])
+ lambda: mapper._get_committed_state_attr_by_column(
+ state, dict_,
+ bind_to_col[bindparam._identifying_key])
else:
def visit_bindparam(bindparam):
- if bindparam.key in bind_to_col:
- bindparam.callable = lambda: mapper._get_state_attr_by_column(
- state, dict_, bind_to_col[bindparam.key])
+ if bindparam._identifying_key in bind_to_col:
+ bindparam.callable = \
+ lambda: mapper._get_state_attr_by_column(
+ state, dict_,
+ bind_to_col[bindparam._identifying_key])
if self.parent_property.secondary is not None and alias_secondary:
@@ -430,14 +439,14 @@ class LazyLoader(AbstractRelationshipLoader):
def _lazy_none_clause(self, reverse_direction=False, adapt_source=None):
if not reverse_direction:
criterion, bind_to_col, rev = \
- self.__lazywhere, \
- self.__bind_to_col,\
+ self._lazywhere, \
+ self._bind_to_col,\
self._equated_columns
else:
criterion, bind_to_col, rev = \
- LazyLoader._create_lazy_clause(
- self.parent_property,
- reverse_direction=reverse_direction)
+ self._rev_lazywhere, \
+ self._rev_bind_to_col, \
+ self._rev_equated_columns
criterion = sql_util.adapt_criterion_to_null(criterion, bind_to_col)
@@ -612,7 +621,7 @@ class LazyLoader(AbstractRelationshipLoader):
if equated in binds:
return None
if col not in binds:
- binds[col] = sql.bindparam(None, None, type_=col.type)
+ binds[col] = sql.bindparam(None, None, type_=col.type, unique=True)
return binds[col]
return None
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 66a87c26f..071bb3c50 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -2498,7 +2498,16 @@ class _BindParamClause(ColumnElement):
else:
self.key = key or _generated_label('%%(%d param)s'
% id(self))
+
+ # identifiying key that won't change across
+ # clones, used to identify the bind's logical
+ # identity
+ self._identifying_key = self.key
+
+ # key that was passed in the first place, used to
+ # generate new keys
self._orig_key = key or 'param'
+
self.unique = unique
self.value = value
self.callable = callable_
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index f003a9691..77c3e45ec 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -194,13 +194,15 @@ def adapt_criterion_to_null(crit, nulls):
"""given criterion containing bind params, convert selected elements to IS NULL."""
def visit_binary(binary):
- if isinstance(binary.left, expression._BindParamClause) and binary.left.key in nulls:
+ if isinstance(binary.left, expression._BindParamClause) \
+ and binary.left._identifying_key in nulls:
# reverse order if the NULL is on the left side
binary.left = binary.right
binary.right = expression.null()
binary.operator = operators.is_
binary.negate = operators.isnot
- elif isinstance(binary.right, expression._BindParamClause) and binary.right.key in nulls:
+ elif isinstance(binary.right, expression._BindParamClause) \
+ and binary.right._identifying_key in nulls:
binary.right = expression.null()
binary.operator = operators.is_
binary.negate = operators.isnot