summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/engine
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/engine')
-rw-r--r--lib/sqlalchemy/engine/base.py20
-rw-r--r--lib/sqlalchemy/engine/default.py25
-rw-r--r--lib/sqlalchemy/engine/result.py42
3 files changed, 77 insertions, 10 deletions
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 4ed3b9af7..34a4f04a9 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -1000,7 +1000,8 @@ class Connection(Connectable):
tuple or scalar positional parameters.
"""
- if isinstance(object_, util.string_types[0]):
+
+ if isinstance(object_, util.string_types):
util.warn_deprecated_20(
"Passing a string to Connection.execute() is "
"deprecated and will be removed in version 2.0. Use the "
@@ -1098,26 +1099,33 @@ class Connection(Connectable):
keys = []
dialect = self.dialect
+
if "compiled_cache" in self._execution_options:
+ elem_cache_key, extracted_params = elem._generate_cache_key()
key = (
dialect,
- elem,
+ elem_cache_key,
tuple(sorted(keys)),
bool(self._schema_translate_map),
len(distilled_params) > 1,
)
- compiled_sql = self._execution_options["compiled_cache"].get(key)
+ cache = self._execution_options["compiled_cache"]
+ compiled_sql = cache.get(key)
+
if compiled_sql is None:
compiled_sql = elem.compile(
dialect=dialect,
+ cache_key=(elem_cache_key, extracted_params),
column_keys=keys,
inline=len(distilled_params) > 1,
schema_translate_map=self._schema_translate_map,
linting=self.dialect.compiler_linting
| compiler.WARN_LINTING,
)
- self._execution_options["compiled_cache"][key] = compiled_sql
+ cache[key] = compiled_sql
+
else:
+ extracted_params = None
compiled_sql = elem.compile(
dialect=dialect,
column_keys=keys,
@@ -1133,6 +1141,8 @@ class Connection(Connectable):
distilled_params,
compiled_sql,
distilled_params,
+ elem,
+ extracted_params,
)
if self._has_events or self.engine._has_events:
self.dispatch.after_execute(self, elem, multiparams, params, ret)
@@ -1156,6 +1166,8 @@ class Connection(Connectable):
parameters,
compiled,
parameters,
+ None,
+ None,
)
if self._has_events or self.engine._has_events:
self.dispatch.after_execute(
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index c44f07538..af61be034 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -750,7 +750,14 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
@classmethod
def _init_compiled(
- cls, dialect, connection, dbapi_connection, compiled, parameters
+ cls,
+ dialect,
+ connection,
+ dbapi_connection,
+ compiled,
+ parameters,
+ invoked_statement,
+ extracted_parameters,
):
"""Initialize execution context for a Compiled construct."""
@@ -758,7 +765,8 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
self.root_connection = connection
self._dbapi_connection = dbapi_connection
self.dialect = connection.dialect
-
+ self.extracted_parameters = extracted_parameters
+ self.invoked_statement = invoked_statement
self.compiled = compiled
# this should be caught in the engine before
@@ -778,7 +786,6 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
compiled._textual_ordered_columns,
compiled._loose_column_name_matching,
)
-
self.isinsert = compiled.isinsert
self.isupdate = compiled.isupdate
self.isdelete = compiled.isdelete
@@ -792,10 +799,18 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
)
if not parameters:
- self.compiled_parameters = [compiled.construct_params()]
+ self.compiled_parameters = [
+ compiled.construct_params(
+ extracted_parameters=extracted_parameters
+ )
+ ]
else:
self.compiled_parameters = [
- compiled.construct_params(m, _group_number=grp)
+ compiled.construct_params(
+ m,
+ _group_number=grp,
+ extracted_parameters=extracted_parameters,
+ )
for grp, m in enumerate(parameters)
]
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index ac033a5ae..986edd617 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -114,6 +114,44 @@ class CursorResultMetaData(ResultMetaData):
"keys",
)
+ def _adapt_to_context(self, context):
+ """When using a cached result metadata against a new context,
+ we need to rewrite the _keymap so that it has the specific
+ Column objects in the new context inside of it. this accommodates
+ for select() constructs that contain anonymized columns and
+ are cached.
+
+ """
+ if not context.compiled._result_columns:
+ return self
+
+ compiled_statement = context.compiled.statement
+ invoked_statement = context.invoked_statement
+
+ # same statement was invoked as the one we cached against,
+ # return self
+ if compiled_statement is invoked_statement:
+ return self
+
+ # make a copy and add the columns from the invoked statement
+ # to the result map.
+ md = self.__class__.__new__(self.__class__)
+
+ md._keymap = self._keymap.copy()
+
+ # match up new columns positionally to the result columns
+ for existing, new in zip(
+ context.compiled._result_columns,
+ invoked_statement._exported_columns_iterator(),
+ ):
+ md._keymap[new] = md._keymap[existing[RM_NAME]]
+
+ md.case_sensitive = self.case_sensitive
+ md.matched_on_name = self.matched_on_name
+ md._processors = self._processors
+ md.keys = self.keys
+ return md
+
def __init__(self, parent, cursor_description):
context = parent.context
dialect = context.dialect
@@ -1107,7 +1145,9 @@ class BaseResult(object):
if strat.cursor_description is not None:
if self.context.compiled:
if self.context.compiled._cached_metadata:
- self._metadata = self.context.compiled._cached_metadata
+ cached_md = self.context.compiled._cached_metadata
+ self._metadata = cached_md._adapt_to_context(self.context)
+
else:
self._metadata = (
self.context.compiled._cached_metadata