diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-08-16 22:38:51 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-08-18 13:25:17 -0400 |
| commit | 0a7ca00e04f7c1cfdbb8bdfe7da5f62fc9b40930 (patch) | |
| tree | 46bb9902bc536d4cf4655b20f68b531725ccf898 /lib | |
| parent | d1948bc69bd0d26fbff77d7525ef899a2a9a580d (diff) | |
| download | sqlalchemy-0a7ca00e04f7c1cfdbb8bdfe7da5f62fc9b40930.tar.gz | |
Revise psycopg2 execute_values approach
Revised the approach for the just added support for the psycopg2
"execute_values()" feature added in 1.3.7 for :ticket:`4623`. The approach
relied upon a regular expression that would fail to match for a more
complex INSERT statement such as one which had subqueries involved. The
new approach matches exactly the string that was rendered as the VALUES
clause.
Fixes: #4623
Change-Id: Icaae0f7b6bcf87a2cf5c6290a839c8429dd5fac3
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/dialects/postgresql/psycopg2.py | 14 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 14 |
2 files changed, 22 insertions, 6 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index 26014dadc..1a4db1108 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -849,8 +849,6 @@ class PGDialect_psycopg2(PGDialect): else: return None - _insert_values_match = re.compile(r".* VALUES (\(.+\))").match - def do_executemany(self, cursor, statement, parameters, context=None): if self.executemany_mode is EXECUTEMANY_DEFAULT: cursor.executemany(statement, parameters) @@ -860,8 +858,14 @@ class PGDialect_psycopg2(PGDialect): self.executemany_mode is EXECUTEMANY_VALUES and context and context.isinsert + and context.compiled.insert_single_values_expr ): - executemany_values = self._insert_values_match(statement) + executemany_values = ( + "(%s)" % context.compiled.insert_single_values_expr + ) + # guard for statement that was altered via event hook or similar + if executemany_values not in statement: + executemany_values = None else: executemany_values = None @@ -870,7 +874,7 @@ class PGDialect_psycopg2(PGDialect): # into executemany(), since no DBAPI has ever supported that # until the introduction of psycopg2's executemany_values, so # we are not yet using the fetch=True flag. - statement = statement.replace(executemany_values.group(1), "%s") + statement = statement.replace(executemany_values, "%s") if self.executemany_values_page_size: kwargs = {"page_size": self.executemany_values_page_size} else: @@ -879,7 +883,7 @@ class PGDialect_psycopg2(PGDialect): cursor, statement, parameters, - template=executemany_values.group(1), + template=executemany_values, **kwargs ) diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 8bd2249e2..fa7eeaecf 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -498,6 +498,15 @@ class SQLCompiler(Compiled): """ + insert_single_values_expr = None + """When an INSERT is compiled with a single set of parameters inside + a VALUES expression, the string is assigned here, where it can be + used for insert batching schemes to rewrite the VALUES expression. + + .. versionadded:: 1.3.8 + + """ + insert_prefetch = update_prefetch = () def __init__( @@ -2512,7 +2521,10 @@ class SQLCompiler(Compiled): ) ) else: - text += " VALUES (%s)" % ", ".join([c[1] for c in crud_params]) + insert_single_values_expr = ", ".join([c[1] for c in crud_params]) + text += " VALUES (%s)" % insert_single_values_expr + if toplevel: + self.insert_single_values_expr = insert_single_values_expr if insert_stmt._post_values_clause is not None: post_values_clause = self.process( |
