From 0e1049600dc88f0f52ff23493ca3aff83a87818f Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 13 Feb 2021 17:13:51 -0500 Subject: [PATCH] expand and further generalize bound parameter translate Continued with the improvement made as part of :ticket:`5653` to further support bound parameter names, including those generated against column names, for names that include colons, parenthesis, and question marks, as well as improved test support, so that bound parameter names even if they are auto-derived from column names should have no problem including for parenthesis in psycopg2's "pyformat" style. As part of this change, the format used by the asyncpg DBAPI adapter (which is local to SQLAlchemy's asyncpg diaelct) has been changed from using "qmark" paramstyle to "format", as there is a standard and internally supported SQL string escaping style for names that use percent signs with "format" style (i.e. to double percent signs), as opposed to names that use question marks with "qmark" style (where an escaping system is not defined by pep-249 or Python). Fixes: #5941 Change-Id: Id86f5af81903d7063a8e3505e60df56490f85358 --- doc/build/changelog/migration_14.rst | 21 +++++ doc/build/changelog/unreleased_14/5941.rst | 22 +++++ lib/sqlalchemy/dialects/postgresql/asyncpg.py | 28 +++---- .../dialects/postgresql/psycopg2.py | 60 +------------ lib/sqlalchemy/sql/compiler.py | 18 ++++ lib/sqlalchemy/testing/suite/test_dialect.py | 49 +++++++++++ test/profiles.txt | 84 +++++++++---------- 7 files changed, 167 insertions(+), 115 deletions(-) create mode 100644 doc/build/changelog/unreleased_14/5941.rst diff --git a/doc/build/changelog/migration_14.rst b/doc/build/changelog/migration_14.rst index 41c91050c0..7bd9f9d315 100644 --- a/doc/build/changelog/migration_14.rst +++ b/doc/build/changelog/migration_14.rst @@ -2577,6 +2577,27 @@ The psycopg2 dialect relies upon many features of psycopg2 released in the past few years. To simplify the dialect, version 2.7, released in March, 2017 is now the minimum version required. +.. _change_5941: + +psycopg2 dialect no longer has limitations regarding bound parameter names +-------------------------------------------------------------------------- + +SQLAlchemy 1.3 was not able to accommodate bound parameter names that included +percent signs or parenthesis under the psycopg2 dialect, which meant that +column names which included these characters were also problematic as +INSERT and other DML statements would generate parameter names that matched +that of the column, unless the :paramref:`_schema.Column.key` parameter +were used to provide an alternate name that would be used to generate +the parameter, or otherwise the parameter style of the dialect had to be +changed. As of SQLAlchemy 1.4.0beta3 all naming limitations have been removed +and parameters are fully escaped in all scenarios. + + +:ticket:`5941` + +:ticket:`5653` + + .. _change_5401: psycopg2 dialect features "execute_values" with RETURNING for INSERT statements by default diff --git a/doc/build/changelog/unreleased_14/5941.rst b/doc/build/changelog/unreleased_14/5941.rst new file mode 100644 index 0000000000..5f5f116f8e --- /dev/null +++ b/doc/build/changelog/unreleased_14/5941.rst @@ -0,0 +1,22 @@ +.. change:: + :tags: bug, engine, postgresql + :tickets: 5941 + + Continued with the improvement made as part of :ticket:`5653` to further + support bound parameter names, including those generated against column + names, for names that include colons, parenthesis, and question marks, as + well as improved test support, so that bound parameter names even if they + are auto-derived from column names should have no problem including for + parenthesis in psycopg2's "pyformat" style. + + As part of this change, the format used by the asyncpg DBAPI adapter (which + is local to SQLAlchemy's asyncpg diaelct) has been changed from using + "qmark" paramstyle to "format", as there is a standard and internally + supported SQL string escaping style for names that use percent signs with + "format" style (i.e. to double percent signs), as opposed to names that use + question marks with "qmark" style (where an escaping system is not defined + by pep-249 or Python). + + .. seealso:: + + :ref:`change_5941` \ No newline at end of file diff --git a/lib/sqlalchemy/dialects/postgresql/asyncpg.py b/lib/sqlalchemy/dialects/postgresql/asyncpg.py index 424ed0d507..7ef5e441cb 100644 --- a/lib/sqlalchemy/dialects/postgresql/asyncpg.py +++ b/lib/sqlalchemy/dialects/postgresql/asyncpg.py @@ -100,7 +100,6 @@ To disable the prepared statement cache, use a value of zero:: import collections import decimal -import itertools import json as _py_json import re import time @@ -357,12 +356,12 @@ class AsyncAdapt_asyncpg_cursor: def _handle_exception(self, error): self._adapt_connection._handle_exception(error) - def _parameters(self): + def _parameter_placeholders(self, params): if not self._inputsizes: - return ("$%d" % idx for idx in itertools.count(1)) + return tuple("$%d" % idx for idx, _ in enumerate(params, 1)) else: - return ( + return tuple( "$%d::%s" % (idx, typ) if typ else "$%d" % idx for idx, typ in enumerate( (_pg_types.get(typ) for typ in self._inputsizes), 1 @@ -374,11 +373,10 @@ class AsyncAdapt_asyncpg_cursor: if not self._adapt_connection._started: await self._adapt_connection._start_transaction() - params = self._parameters() - - # TODO: would be nice to support the dollar numeric thing - # directly, this is much easier for now - operation = re.sub(r"\?", lambda m: next(params), operation) + if parameters is not None: + operation = operation % self._parameter_placeholders(parameters) + else: + parameters = () try: prepared_stmt, attributes = await self._adapt_connection._prepare( @@ -409,7 +407,7 @@ class AsyncAdapt_asyncpg_cursor: except Exception as error: self._handle_exception(error) - def execute(self, operation, parameters=()): + def execute(self, operation, parameters=None): try: self._adapt_connection.await_( self._prepare_and_execute(operation, parameters) @@ -429,8 +427,10 @@ class AsyncAdapt_asyncpg_cursor: if not adapt_connection._started: adapt_connection.await_(adapt_connection._start_transaction()) - params = self._parameters() - operation = re.sub(r"\?", lambda m: next(params), operation) + operation = operation % self._parameter_placeholders( + seq_of_parameters[0] + ) + try: return adapt_connection.await_( self._connection.executemany(operation, seq_of_parameters) @@ -706,7 +706,7 @@ class AsyncAdaptFallback_asyncpg_connection(AsyncAdapt_asyncpg_connection): class AsyncAdapt_asyncpg_dbapi: def __init__(self, asyncpg): self.asyncpg = asyncpg - self.paramstyle = "qmark" + self.paramstyle = "format" def connect(self, *arg, **kw): async_fallback = kw.pop("async_fallback", False) @@ -837,7 +837,7 @@ class PGDialect_asyncpg(PGDialect): supports_unicode_binds = True - default_paramstyle = "qmark" + default_paramstyle = "format" supports_sane_multi_rowcount = False execution_ctx_cls = PGExecutionContext_asyncpg statement_compiler = PGCompiler_asyncpg diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index b1d27c6faa..a52eacd8bc 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -323,57 +323,6 @@ on the way in and coerce from bytes on the way back, using the value of the SQLAlchemy's own unicode encode/decode functionality is steadily becoming obsolete as most DBAPIs now support unicode fully. -Bound Parameter Styles ----------------------- - -The default parameter style for the psycopg2 dialect is "pyformat", where -SQL is rendered using ``%(paramname)s`` style. This format has the limitation -that it does not accommodate the unusual case of parameter names that -actually contain percent or parenthesis symbols; as SQLAlchemy in many cases -generates bound parameter names based on the name of a column, the presence -of these characters in a column name can lead to problems. - -There are two solutions to the issue of a :class:`_schema.Column` -that contains -one of these characters in its name. One is to specify the -:paramref:`.schema.Column.key` for columns that have such names:: - - measurement = Table('measurement', metadata, - Column('Size (meters)', Integer, key='size_meters') - ) - -Above, an INSERT statement such as ``measurement.insert()`` will use -``size_meters`` as the parameter name, and a SQL expression such as -``measurement.c.size_meters > 10`` will derive the bound parameter name -from the ``size_meters`` key as well. - -.. versionchanged:: 1.0.0 - SQL expressions will use - :attr:`_schema.Column.key` - as the source of naming when anonymous bound parameters are created - in SQL expressions; previously, this behavior only applied to - :meth:`_schema.Table.insert` and :meth:`_schema.Table.update` - parameter names. - -The other solution is to use a positional format; psycopg2 allows use of the -"format" paramstyle, which can be passed to -:paramref:`_sa.create_engine.paramstyle`:: - - engine = create_engine( - 'postgresql://scott:tiger@localhost:5432/test', paramstyle='format') - -With the above engine, instead of a statement like:: - - INSERT INTO measurement ("Size (meters)") VALUES (%(Size (meters))s) - {'Size (meters)': 1} - -we instead see:: - - INSERT INTO measurement ("Size (meters)") VALUES (%s) - (1, ) - -Where above, the dictionary style is converted into a tuple with positional -style. - Transactions ------------ @@ -648,14 +597,7 @@ class PGExecutionContext_psycopg2(PGExecutionContext): class PGCompiler_psycopg2(PGCompiler): - def bindparam_string(self, name, **kw): - if "%" in name and not kw.get("post_compile", False): - # psycopg2 will not allow a percent sign in a - # pyformat parameter name even if it is doubled - kw["escaped_from"] = name - name = name.replace("%", "P") - - return PGCompiler.bindparam_string(self, name, **kw) + pass class PGIdentifierPreparer_psycopg2(PGIdentifierPreparer): diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index f22e8614bc..763b4cabbd 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -166,6 +166,11 @@ BIND_TEMPLATES = { "named": ":%(name)s", } +BIND_TRANSLATE = { + "pyformat": re.compile(r"[%\(\)]"), + "named": re.compile(r"[\:]"), +} +_BIND_TRANSLATE_CHARS = {"%": "P", "(": "A", ")": "Z", ":": "C"} OPERATORS = { # binary @@ -765,6 +770,7 @@ class SQLCompiler(Compiled): self.positiontup = [] self._numeric_binds = dialect.paramstyle == "numeric" self.bindtemplate = BIND_TEMPLATES[dialect.paramstyle] + self._bind_translate = BIND_TRANSLATE.get(dialect.paramstyle, None) self.ctes = None @@ -2417,11 +2423,23 @@ class SQLCompiler(Compiled): escaped_from=None, **kw ): + if self.positional: if positional_names is not None: positional_names.append(name) else: self.positiontup.append(name) + elif not post_compile and not escaped_from: + tr_reg = self._bind_translate + if tr_reg.search(name): + # i'd rather use translate() here but I can't get it to work + # in all cases under Python 2, not worth it right now + new_name = tr_reg.sub( + lambda m: _BIND_TRANSLATE_CHARS[m.group(0)], + name, + ) + escaped_from = name + name = new_name if escaped_from: if not self.escaped_bind_names: diff --git a/lib/sqlalchemy/testing/suite/test_dialect.py b/lib/sqlalchemy/testing/suite/test_dialect.py index 8709aca9d3..a236b10769 100644 --- a/lib/sqlalchemy/testing/suite/test_dialect.py +++ b/lib/sqlalchemy/testing/suite/test_dialect.py @@ -1,5 +1,6 @@ #! coding: utf-8 +from . import testing from .. import assert_raises from .. import config from .. import engines @@ -11,6 +12,7 @@ from ..config import requirements from ..provision import set_default_schema_on_connection from ..schema import Column from ..schema import Table +from ... import bindparam from ... import event from ... import exc from ... import Integer @@ -308,3 +310,50 @@ class FutureWeCanSetDefaultSchemaWEventsTest( fixtures.FutureEngineMixin, WeCanSetDefaultSchemaWEventsTest ): pass + + +class DifficultParametersTest(fixtures.TestBase): + __backend__ = True + + @testing.combinations( + ("boring",), + ("per cent",), + ("per % cent",), + ("%percent",), + ("par(ens)",), + ("percent%(ens)yah",), + ("col:ons",), + ("more :: %colons%",), + ("/slashes/",), + ("more/slashes",), + ("q?marks",), + ("1param",), + ("1col:on",), + argnames="name", + ) + def test_round_trip(self, name, connection, metadata): + t = Table( + "t", + metadata, + Column("id", Integer, primary_key=True), + Column(name, String(50), nullable=False), + ) + + # table is created + t.create(connection) + + # automatic param generated by insert + connection.execute(t.insert().values({"id": 1, name: "some name"})) + + # automatic param generated by criteria, plus selecting the column + stmt = select(t.c[name]).where(t.c[name] == "some name") + + eq_(connection.scalar(stmt), "some name") + + # use the name in a param explicitly + stmt = select(t.c[name]).where(t.c[name] == bindparam(name)) + + row = connection.execute(stmt, {name: "some name"}).first() + + # name works as the key from cursor.description + eq_(row._mapping[name], "some name") diff --git a/test/profiles.txt b/test/profiles.txt index 2a43da63aa..a5f06b5c9f 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -13,38 +13,38 @@ # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_mysqldb_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_mysqldb_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_pymysql_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_pymysql_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mssql_pyodbc_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mssql_pyodbc_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_cextensions 62 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_nocextensions 62 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 64 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_pymysql_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_pymysql_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_pymysql_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_pymysql_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_cextensions 67 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_nocextensions 67 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_nocextensions 69 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_mysqldb_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_mysqldb_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_pymysql_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mariadb_pymysql_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mssql_pyodbc_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mssql_pyodbc_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_cextensions 66 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_nocextensions 66 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 68 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_pymysql_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mariadb_pymysql_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_pymysql_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_mysql_pymysql_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_cextensions 71 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_nocextensions 71 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_nocextensions 73 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_select @@ -112,8 +112,8 @@ test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2. test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_nocextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_cextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_nocextensions 69 -test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_cextensions 67 -test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_nocextensions 67 +test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_cextensions 79 +test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_nocextensions 79 test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_cextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 69 @@ -137,14 +137,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_3. # TEST: test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 165 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 165 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 165 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_nocextensions 165 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_cextensions 169 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 169 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 169 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 169 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 175 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 175 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 175 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_nocextensions 175 # TEST: test.aaa_profiling.test_misc.CacheKeyTest.test_statement_key_is_cached -- 2.47.2