diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2019-10-05 00:05:33 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2019-10-05 00:05:33 +0000 |
| commit | c6abd4766abb0396c9bf532d81d16226b970a35a (patch) | |
| tree | 5ac87ae9557926cceacc2a58ece4b43053a6798f /lib/sqlalchemy/sql | |
| parent | b73c191903d5f23b02188474f6a8a1b877988a40 (diff) | |
| parent | 485216dea6d7a5814d200b4f14b8a363ed0f8caa (diff) | |
| download | sqlalchemy-c6abd4766abb0396c9bf532d81d16226b970a35a.tar.gz | |
Merge "Deprecate textual column matching in Row"
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 29 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 9 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/selectable.py | 5 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 4 |
4 files changed, 38 insertions, 9 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 5e432a74c..1381e734c 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -490,6 +490,13 @@ class SQLCompiler(Compiled): True unless using an unordered TextualSelect. """ + _loose_column_name_matching = False + """tell the result object that the SQL staement is textual, wants to match + up to Column objects, and may be using the ._label in the SELECT rather + than the base name. + + """ + _numeric_binds = False """ True if paramstyle is "numeric". This paramstyle is trickier than @@ -799,6 +806,7 @@ class SQLCompiler(Compiled): within_label_clause=False, within_columns_clause=False, render_label_as_label=None, + result_map_targets=(), **kw ): # only render labels within the columns clause @@ -820,7 +828,7 @@ class SQLCompiler(Compiled): add_to_result_map( labelname, label.name, - (label, labelname) + label._alt_names, + (label, labelname) + label._alt_names + result_map_targets, label.type, ) @@ -847,7 +855,12 @@ class SQLCompiler(Compiled): ) def visit_column( - self, column, add_to_result_map=None, include_table=True, **kwargs + self, + column, + add_to_result_map=None, + include_table=True, + result_map_targets=(), + **kwargs ): name = orig_name = column.name if name is None: @@ -859,7 +872,10 @@ class SQLCompiler(Compiled): if add_to_result_map is not None: add_to_result_map( - name, orig_name, (column, name, column.key), column.type + name, + orig_name, + (column, name, column.key, column._label) + result_map_targets, + column.type, ) if is_literal: @@ -948,6 +964,13 @@ class SQLCompiler(Compiled): self._ordered_columns = ( self._textual_ordered_columns ) = taf.positional + + # enable looser result column matching when the SQL text links to + # Column objects by name only + self._loose_column_name_matching = not taf.positional and bool( + taf.column_args + ) + for c in taf.column_args: self.process( c, diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 3045cb84e..8ee157b6f 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -4278,7 +4278,13 @@ class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement): label = quoted_name(label, t.name.quote) # ensure the label name doesn't conflict with that - # of an existing column + # of an existing column. note that this implies that any + # Column must **not** set up its _label before its parent table + # has all of its other Column objects set up. There are several + # tables in the test suite which will fail otherwise; example: + # table "owner" has columns "name" and "owner_name". Therefore + # column owner.name cannot use the label "owner_name", it has + # to be "owner_name_1". if label in t.c: _label = label counter = 1 @@ -4339,7 +4345,6 @@ class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement): c._proxies = [self] if selectable._is_clone_of is not None: c._is_clone_of = selectable._is_clone_of.columns.get(c.key) - return c.key, c diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index b41a77622..33ba95717 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -4449,7 +4449,10 @@ class TextualSelect(SelectBase): def __init__(self, text, columns, positional=False): self.element = text - self.column_args = columns + # convert for ORM attributes->columns, etc + self.column_args = [ + coercions.expect(roles.ColumnsClauseRole, c) for c in columns + ] self.positional = positional @SelectBase._memoized_property diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 780cdc7b2..5aeed0c1c 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -798,9 +798,7 @@ class ClauseAdapter(visitors.ReplacingCloningVisitor): if newcol is not None: return newcol if self.adapt_on_names and newcol is None: - # TODO: this should be changed to .exported_columns if and - # when we need to be able to adapt a plain Select statement - newcol = self.selectable.c.get(col.name) + newcol = self.selectable.exported_columns.get(col.name) return newcol def replace(self, col): |
