diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-07-06 12:35:45 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-07-06 12:35:45 -0400 |
| commit | 5b8738b7e390471bd31b9ece90d0a3fd7653d859 (patch) | |
| tree | 81b520b5ef6dd004f61112441d8b0c5bd76270a5 /lib | |
| parent | 138774b234457bde1af522062be74403d71ea7d9 (diff) | |
| download | sqlalchemy-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.py | 51 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/expression.py | 9 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 6 |
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 |
