summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/core/tutorial.rst8
-rw-r--r--lib/sqlalchemy/cextension/utils.c27
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py20
-rw-r--r--lib/sqlalchemy/engine/base.py187
-rw-r--r--lib/sqlalchemy/engine/util.py73
-rw-r--r--lib/sqlalchemy/testing/assertsql.py6
-rw-r--r--test/aaa_profiling/test_resultset.py4
-rw-r--r--test/dialect/postgresql/test_query.py15
-rw-r--r--test/engine/test_deprecations.py90
-rw-r--r--test/engine/test_execute.py121
-rw-r--r--test/engine/test_processors.py34
-rw-r--r--test/profiles.txt29
12 files changed, 477 insertions, 137 deletions
diff --git a/doc/build/core/tutorial.rst b/doc/build/core/tutorial.rst
index 3f4d37d0e..8d27dd21d 100644
--- a/doc/build/core/tutorial.rst
+++ b/doc/build/core/tutorial.rst
@@ -323,7 +323,7 @@ and use it in the "normal" way:
.. sourcecode:: pycon+sql
>>> ins = users.insert()
- >>> conn.execute(ins, id=2, name='wendy', fullname='Wendy Williams')
+ >>> conn.execute(ins, {"id": 2, "name":"wendy", "fullname": "Wendy Williams"})
{opensql}INSERT INTO users (id, name, fullname) VALUES (?, ?, ?)
[...] (2, 'wendy', 'Wendy Williams')
COMMIT
@@ -972,7 +972,7 @@ unchanged. Below, we create a :func:`_expression.text` object and execute it:
... "AND users.name BETWEEN :x AND :y "
... "AND (addresses.email_address LIKE :e1 "
... "OR addresses.email_address LIKE :e2)")
- >>> conn.execute(s, x='m', y='z', e1='%@aol.com', e2='%@msn.com').fetchall()
+ >>> conn.execute(s, {"x":"m", "y":"z", "e1":"%@aol.com", "e2":"%@msn.com"}).fetchall()
{opensql}SELECT users.fullname || ', ' || addresses.email_address AS title
FROM users, addresses
WHERE users.id = addresses.user_id AND users.name BETWEEN ? AND ? AND
@@ -1127,7 +1127,7 @@ need to refer to any pre-established :class:`_schema.Table` metadata:
... "OR addresses.email_address LIKE :y)")
... )
... ).select_from(text('users, addresses'))
- >>> conn.execute(s, x='%@aol.com', y='%@msn.com').fetchall()
+ >>> conn.execute(s, {"x": "%@aol.com", "y": "%@msn.com"}).fetchall()
{opensql}SELECT users.fullname || ', ' || addresses.email_address AS title
FROM users, addresses
WHERE users.id = addresses.user_id AND users.name BETWEEN 'm' AND 'z'
@@ -1180,7 +1180,7 @@ be quoted:
... )
... ).select_from(table('users')).select_from(table('addresses'))
- >>> conn.execute(s, x='%@aol.com', y='%@msn.com').fetchall()
+ >>> conn.execute(s, {"x":"%@aol.com", "y":"%@msn.com"}).fetchall()
{opensql}SELECT users.fullname || ? || addresses.email_address AS anon_1
FROM users, addresses
WHERE users.id = addresses.user_id
diff --git a/lib/sqlalchemy/cextension/utils.c b/lib/sqlalchemy/cextension/utils.c
index ab8b39335..c612094dc 100644
--- a/lib/sqlalchemy/cextension/utils.c
+++ b/lib/sqlalchemy/cextension/utils.c
@@ -26,12 +26,13 @@ distill_params(PyObject *self, PyObject *args)
// TODO: pass the Connection in so that there can be a standard
// method for warning on parameter format
- PyObject *multiparams, *params;
+ PyObject *connection, *multiparams, *params;
PyObject *enclosing_list, *double_enclosing_list;
PyObject *zero_element, *zero_element_item;
+ PyObject *tmp;
Py_ssize_t multiparam_size, zero_element_length;
- if (!PyArg_UnpackTuple(args, "_distill_params", 2, 2, &multiparams, &params)) {
+ if (!PyArg_UnpackTuple(args, "_distill_params", 3, 3, &connection, &multiparams, &params)) {
return NULL;
}
@@ -47,8 +48,12 @@ distill_params(PyObject *self, PyObject *args)
if (multiparam_size == 0) {
if (params != Py_None && PyMapping_Size(params) != 0) {
- // TODO: this is keyword parameters, emit parameter format
- // deprecation warning
+
+ tmp = PyObject_CallMethod(connection, "_warn_for_legacy_exec_format", "");
+ if (tmp == NULL) {
+ return NULL;
+ }
+
enclosing_list = PyList_New(1);
if (enclosing_list == NULL) {
return NULL;
@@ -102,6 +107,7 @@ distill_params(PyObject *self, PyObject *args)
* execute(stmt, ("value", "value"))
*/
Py_XDECREF(zero_element_item);
+
enclosing_list = PyList_New(1);
if (enclosing_list == NULL) {
return NULL;
@@ -131,6 +137,11 @@ distill_params(PyObject *self, PyObject *args)
}
return enclosing_list;
} else {
+ tmp = PyObject_CallMethod(connection, "_warn_for_legacy_exec_format", "");
+ if (tmp == NULL) {
+ return NULL;
+ }
+
enclosing_list = PyList_New(1);
if (enclosing_list == NULL) {
return NULL;
@@ -157,8 +168,12 @@ distill_params(PyObject *self, PyObject *args)
}
}
else {
- // TODO: this is multiple positional params, emit parameter format
- // deprecation warning
+
+ tmp = PyObject_CallMethod(connection, "_warn_for_legacy_exec_format", "");
+ if (tmp == NULL) {
+ return NULL;
+ }
+
zero_element = PyTuple_GetItem(multiparams, 0);
if (PyObject_HasAttrString(zero_element, "__iter__") &&
!PyObject_HasAttrString(zero_element, "strip")
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 2db079799..c56cccd8d 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -2903,7 +2903,11 @@ class PGDialect(default.DefaultDialect):
"JOIN pg_namespace n ON n.oid = c.relnamespace "
"WHERE n.nspname = :schema AND c.relkind in ('r', 'p')"
).columns(relname=sqltypes.Unicode),
- schema=schema if schema is not None else self.default_schema_name,
+ dict(
+ schema=schema
+ if schema is not None
+ else self.default_schema_name
+ ),
)
return [name for name, in result]
@@ -3018,7 +3022,7 @@ class PGDialect(default.DefaultDialect):
.bindparams(sql.bindparam("table_oid", type_=sqltypes.Integer))
.columns(attname=sqltypes.Unicode, default=sqltypes.Unicode)
)
- c = connection.execute(s, table_oid=table_oid)
+ c = connection.execute(s, dict(table_oid=table_oid))
rows = c.fetchall()
# dictionary with (name, ) if default search path or (schema, name)
@@ -3260,7 +3264,7 @@ class PGDialect(default.DefaultDialect):
ORDER BY k.ord
"""
t = sql.text(PK_SQL).columns(attname=sqltypes.Unicode)
- c = connection.execute(t, table_oid=table_oid)
+ c = connection.execute(t, dict(table_oid=table_oid))
cols = [r[0] for r in c.fetchall()]
PK_CONS_SQL = """
@@ -3270,7 +3274,7 @@ class PGDialect(default.DefaultDialect):
ORDER BY 1
"""
t = sql.text(PK_CONS_SQL).columns(conname=sqltypes.Unicode)
- c = connection.execute(t, table_oid=table_oid)
+ c = connection.execute(t, dict(table_oid=table_oid))
name = c.scalar()
return {"constrained_columns": cols, "name": name}
@@ -3318,7 +3322,7 @@ class PGDialect(default.DefaultDialect):
t = sql.text(FK_SQL).columns(
conname=sqltypes.Unicode, condef=sqltypes.Unicode
)
- c = connection.execute(t, table=table_oid)
+ c = connection.execute(t, dict(table=table_oid))
fkeys = []
for conname, condef, conschema in c.fetchall():
m = re.search(FK_REGEX, condef).groups()
@@ -3490,7 +3494,7 @@ class PGDialect(default.DefaultDialect):
t = sql.text(IDX_SQL).columns(
relname=sqltypes.Unicode, attname=sqltypes.Unicode
)
- c = connection.execute(t, table_oid=table_oid)
+ c = connection.execute(t, dict(table_oid=table_oid))
indexes = defaultdict(lambda: defaultdict(dict))
@@ -3632,7 +3636,7 @@ class PGDialect(default.DefaultDialect):
"""
t = sql.text(UNIQUE_SQL).columns(col_name=sqltypes.Unicode)
- c = connection.execute(t, table_oid=table_oid)
+ c = connection.execute(t, dict(table_oid=table_oid))
uniques = defaultdict(lambda: defaultdict(dict))
for row in c.fetchall():
@@ -3683,7 +3687,7 @@ class PGDialect(default.DefaultDialect):
cons.contype = 'c'
"""
- c = connection.execute(sql.text(CHECK_SQL), table_oid=table_oid)
+ c = connection.execute(sql.text(CHECK_SQL), dict(table_oid=table_oid))
ret = []
for name, src in c:
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 34bf720b7..0eaa1fae1 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -935,6 +935,17 @@ class Connection(Connectable):
if not self.in_transaction():
self._rollback_impl()
+ def _warn_for_legacy_exec_format(self):
+ util.warn_deprecated_20(
+ "The connection.execute() method in "
+ "SQLAlchemy 2.0 will accept parameters as a single "
+ "dictionary or a "
+ "single sequence of dictionaries only. "
+ "Parameters passed as keyword arguments, tuples or positionally "
+ "oriened dictionaries and/or tuples "
+ "will no longer be accepted."
+ )
+
def close(self):
"""Close this :class:`_engine.Connection`.
@@ -1073,14 +1084,13 @@ class Connection(Connectable):
"or the Connection.exec_driver_sql() method to invoke a "
"driver-level SQL string."
)
- distilled_parameters = _distill_params(multiparams, params)
return self._exec_driver_sql(
object_,
multiparams,
params,
- distilled_parameters,
_EMPTY_EXECUTION_OPTS,
+ future=False,
)
try:
@@ -1113,11 +1123,16 @@ class Connection(Connectable):
execution_options
)
+ distilled_parameters = _distill_params(self, multiparams, params)
+
if self._has_events or self.engine._has_events:
- for fn in self.dispatch.before_execute:
- default, multiparams, params = fn(
- self, default, multiparams, params, execution_options
- )
+ (
+ distilled_params,
+ event_multiparams,
+ event_params,
+ ) = self._invoke_before_exec_event(
+ default, distilled_parameters, execution_options
+ )
try:
conn = self._dbapi_connection
@@ -1139,7 +1154,12 @@ class Connection(Connectable):
if self._has_events or self.engine._has_events:
self.dispatch.after_execute(
- self, default, multiparams, params, execution_options, ret
+ self,
+ default,
+ event_multiparams,
+ event_params,
+ execution_options,
+ ret,
)
return ret
@@ -1151,11 +1171,16 @@ class Connection(Connectable):
self._execution_options, execution_options
)
+ distilled_parameters = _distill_params(self, multiparams, params)
+
if self._has_events or self.engine._has_events:
- for fn in self.dispatch.before_execute:
- ddl, multiparams, params = fn(
- self, ddl, multiparams, params, execution_options
- )
+ (
+ distilled_params,
+ event_multiparams,
+ event_params,
+ ) = self._invoke_before_exec_event(
+ ddl, distilled_parameters, execution_options
+ )
exec_opts = self._execution_options.merge_with(execution_options)
schema_translate_map = exec_opts.get("schema_translate_map", None)
@@ -1175,10 +1200,43 @@ class Connection(Connectable):
)
if self._has_events or self.engine._has_events:
self.dispatch.after_execute(
- self, ddl, multiparams, params, execution_options, ret
+ self,
+ ddl,
+ event_multiparams,
+ event_params,
+ execution_options,
+ ret,
)
return ret
+ def _invoke_before_exec_event(
+ self, elem, distilled_params, execution_options
+ ):
+
+ if len(distilled_params) == 1:
+ event_multiparams, event_params = [], distilled_params[0]
+ else:
+ event_multiparams, event_params = distilled_params, {}
+
+ for fn in self.dispatch.before_execute:
+ elem, event_multiparams, event_params = fn(
+ self, elem, event_multiparams, event_params, execution_options,
+ )
+
+ if event_multiparams:
+ distilled_params = list(event_multiparams)
+ if event_params:
+ raise exc.InvalidRequestError(
+ "Event handler can't return non-empty multiparams "
+ "and params at the same time"
+ )
+ elif event_params:
+ distilled_params = [event_params]
+ else:
+ distilled_params = []
+
+ return distilled_params, event_multiparams, event_params
+
def _execute_clauseelement(
self, elem, multiparams, params, execution_options
):
@@ -1188,14 +1246,18 @@ class Connection(Connectable):
self._execution_options, execution_options
)
+ distilled_params = _distill_params(self, multiparams, params)
+
has_events = self._has_events or self.engine._has_events
if has_events:
- for fn in self.dispatch.before_execute:
- elem, multiparams, params = fn(
- self, elem, multiparams, params, execution_options
- )
+ (
+ distilled_params,
+ event_multiparams,
+ event_params,
+ ) = self._invoke_before_exec_event(
+ elem, distilled_params, execution_options
+ )
- distilled_params = _distill_params(multiparams, params)
if distilled_params:
# ensure we don't retain a link to the view object for keys()
# which links to the values, which we don't want to cache
@@ -1237,7 +1299,12 @@ class Connection(Connectable):
)
if has_events:
self.dispatch.after_execute(
- self, elem, multiparams, params, execution_options, ret
+ self,
+ elem,
+ event_multiparams,
+ event_params,
+ execution_options,
+ ret,
)
return ret
@@ -1257,49 +1324,58 @@ class Connection(Connectable):
execution_options = compiled.execution_options.merge_with(
self._execution_options, execution_options
)
+ distilled_parameters = _distill_params(self, multiparams, params)
if self._has_events or self.engine._has_events:
- for fn in self.dispatch.before_execute:
- compiled, multiparams, params = fn(
- self, compiled, multiparams, params, execution_options
- )
+ (
+ distilled_params,
+ event_multiparams,
+ event_params,
+ ) = self._invoke_before_exec_event(
+ compiled, distilled_parameters, execution_options
+ )
dialect = self.dialect
- parameters = _distill_params(multiparams, params)
ret = self._execute_context(
dialect,
dialect.execution_ctx_cls._init_compiled,
compiled,
- parameters,
+ distilled_parameters,
execution_options,
compiled,
- parameters,
+ distilled_parameters,
None,
None,
)
if self._has_events or self.engine._has_events:
self.dispatch.after_execute(
- self, compiled, multiparams, params, execution_options, ret
+ self,
+ compiled,
+ event_multiparams,
+ event_params,
+ execution_options,
+ ret,
)
return ret
def _exec_driver_sql(
- self,
- statement,
- multiparams,
- params,
- distilled_parameters,
- execution_options,
+ self, statement, multiparams, params, execution_options, future
):
execution_options = self._execution_options.merge_with(
execution_options
)
- if self._has_events or self.engine._has_events:
- for fn in self.dispatch.before_execute:
- statement, multiparams, params = fn(
- self, statement, multiparams, params, execution_options
+ distilled_parameters = _distill_params(self, multiparams, params)
+
+ if not future:
+ if self._has_events or self.engine._has_events:
+ (
+ distilled_params,
+ event_multiparams,
+ event_params,
+ ) = self._invoke_before_exec_event(
+ statement, distilled_parameters, execution_options
)
dialect = self.dialect
@@ -1312,10 +1388,17 @@ class Connection(Connectable):
statement,
distilled_parameters,
)
- if self._has_events or self.engine._has_events:
- self.dispatch.after_execute(
- self, statement, multiparams, params, execution_options, ret
- )
+
+ if not future:
+ if self._has_events or self.engine._has_events:
+ self.dispatch.after_execute(
+ self,
+ statement,
+ event_multiparams,
+ event_params,
+ execution_options,
+ ret,
+ )
return ret
def _execute_20(
@@ -1324,9 +1407,7 @@ class Connection(Connectable):
parameters=None,
execution_options=_EMPTY_EXECUTION_OPTS,
):
- multiparams, params, distilled_parameters = _distill_params_20(
- parameters
- )
+ args_10style, kwargs_10style = _distill_params_20(parameters)
try:
meth = statement._execute_on_connection
except AttributeError as err:
@@ -1334,7 +1415,7 @@ class Connection(Connectable):
exc.ObjectNotExecutableError(statement), replace_context=err
)
else:
- return meth(self, multiparams, params, execution_options)
+ return meth(self, args_10style, kwargs_10style, execution_options)
def exec_driver_sql(
self, statement, parameters=None, execution_options=None
@@ -1373,22 +1454,28 @@ class Connection(Connectable):
(1, 'v1')
)
+ .. note:: The :meth:`_engine.Connection.exec_driver_sql` method does
+ not participate in the
+ :meth:`_events.ConnectionEvents.before_execute` and
+ :meth:`_events.ConnectionEvents.after_execute` events. To
+ intercept calls to :meth:`_engine.Connection.exec_driver_sql`, use
+ :meth:`_events.ConnectionEvents.before_cursor_execute` and
+ :meth:`_events.ConnectionEvents.after_cursor_execute`.
+
.. seealso::
:pep:`249`
"""
- multiparams, params, distilled_parameters = _distill_params_20(
- parameters
- )
+ args_10style, kwargs_10style = _distill_params_20(parameters)
return self._exec_driver_sql(
statement,
- multiparams,
- params,
- distilled_parameters,
+ args_10style,
+ kwargs_10style,
execution_options,
+ future=True,
)
def _execute_context(
diff --git a/lib/sqlalchemy/engine/util.py b/lib/sqlalchemy/engine/util.py
index fc0260ae2..c1f6bad77 100644
--- a/lib/sqlalchemy/engine/util.py
+++ b/lib/sqlalchemy/engine/util.py
@@ -30,10 +30,14 @@ def connection_memoize(key):
return decorated
+_no_tuple = ()
+_no_kw = util.immutabledict()
+
+
def py_fallback():
# TODO: pass the Connection in so that there can be a standard
# method for warning on parameter format
- def _distill_params(multiparams, params): # noqa
+ def _distill_params(connection, multiparams, params): # noqa
r"""Given arguments from the calling form \*multiparams, \**params,
return a list of bind parameter structures, usually a list of
dictionaries.
@@ -43,9 +47,12 @@ def py_fallback():
"""
+ # C version will fail if this assertion is not true.
+ # assert isinstance(multiparams, tuple)
+
if not multiparams:
if params:
- # TODO: parameter format deprecation warning
+ connection._warn_for_legacy_exec_format()
return [params]
else:
return []
@@ -61,16 +68,22 @@ def py_fallback():
# execute(stmt, [(), (), (), ...])
return zero
else:
+ # this is used by exec_driver_sql only, so a deprecation
+ # warning would already be coming from passing a plain
+ # textual statement with positional parameters to
+ # execute().
# execute(stmt, ("value", "value"))
+
return [zero]
elif hasattr(zero, "keys"):
# execute(stmt, {"key":"value"})
return [zero]
else:
+ connection._warn_for_legacy_exec_format()
# execute(stmt, "value")
return [[zero]]
else:
- # TODO: parameter format deprecation warning
+ connection._warn_for_legacy_exec_format()
if hasattr(multiparams[0], "__iter__") and not hasattr(
multiparams[0], "strip"
):
@@ -81,14 +94,55 @@ def py_fallback():
return locals()
-_no_tuple = ()
-_no_kw = util.immutabledict()
+def _distill_cursor_params(connection, multiparams, params):
+ """_distill_params without any warnings. more appropriate for
+ "cursor" params that can include tuple arguments, lists of tuples,
+ etc.
+
+ """
+
+ if not multiparams:
+ if params:
+ return [params]
+ else:
+ return []
+ elif len(multiparams) == 1:
+ zero = multiparams[0]
+ if isinstance(zero, (list, tuple)):
+ if (
+ not zero
+ or hasattr(zero[0], "__iter__")
+ and not hasattr(zero[0], "strip")
+ ):
+ # execute(stmt, [{}, {}, {}, ...])
+ # execute(stmt, [(), (), (), ...])
+ return zero
+ else:
+ # this is used by exec_driver_sql only, so a deprecation
+ # warning would already be coming from passing a plain
+ # textual statement with positional parameters to
+ # execute().
+ # execute(stmt, ("value", "value"))
+
+ return [zero]
+ elif hasattr(zero, "keys"):
+ # execute(stmt, {"key":"value"})
+ return [zero]
+ else:
+ # execute(stmt, "value")
+ return [[zero]]
+ else:
+ if hasattr(multiparams[0], "__iter__") and not hasattr(
+ multiparams[0], "strip"
+ ):
+ return multiparams
+ else:
+ return [multiparams]
def _distill_params_20(params):
- # TODO: this has to be in C
if params is None:
- return _no_tuple, _no_kw, []
+ return _no_tuple, _no_kw
elif isinstance(params, list):
# collections_abc.MutableSequence): # avoid abc.__instancecheck__
if params and not isinstance(
@@ -98,15 +152,14 @@ def _distill_params_20(params):
"List argument must consist only of tuples or dictionaries"
)
- # the tuple is needed atm by the C version of _distill_params...
- return tuple(params), _no_kw, params
+ return (params,), _no_kw
elif isinstance(
params,
(tuple, dict, immutabledict),
# avoid abc.__instancecheck__
# (collections_abc.Sequence, collections_abc.Mapping),
):
- return _no_tuple, params, [params]
+ return (params,), _no_kw
else:
raise exc.ArgumentError("mapping or sequence expected for parameters")
diff --git a/lib/sqlalchemy/testing/assertsql.py b/lib/sqlalchemy/testing/assertsql.py
index 73b062b96..c86e26ccf 100644
--- a/lib/sqlalchemy/testing/assertsql.py
+++ b/lib/sqlalchemy/testing/assertsql.py
@@ -13,7 +13,7 @@ from .. import event
from .. import util
from ..engine import url
from ..engine.default import DefaultDialect
-from ..engine.util import _distill_params
+from ..engine.util import _distill_cursor_params
from ..schema import _DDLCompiles
@@ -348,7 +348,9 @@ class SQLExecuteObserved(object):
def __init__(self, context, clauseelement, multiparams, params):
self.context = context
self.clauseelement = clauseelement
- self.parameters = _distill_params(multiparams, params)
+ self.parameters = _distill_cursor_params(
+ context.connection, tuple(multiparams), params
+ )
self.statements = []
def __repr__(self):
diff --git a/test/aaa_profiling/test_resultset.py b/test/aaa_profiling/test_resultset.py
index 119a5ee6a..aea160c9e 100644
--- a/test/aaa_profiling/test_resultset.py
+++ b/test/aaa_profiling/test_resultset.py
@@ -98,7 +98,7 @@ class ResultSetTest(fixtures.TestBase, AssertsExecutionResults):
) as conn:
[tuple(row) for row in conn.execute(t2.select()).fetchall()]
- @profiling.function_call_count(variance=0.10)
+ @profiling.function_call_count(variance=0.15)
def test_raw_string(self):
stmt = "SELECT %s FROM table1" % (
", ".join("field%d" % fnum for fnum in range(NUM_FIELDS))
@@ -106,7 +106,7 @@ class ResultSetTest(fixtures.TestBase, AssertsExecutionResults):
with testing.db.connect() as conn:
[tuple(row) for row in conn.exec_driver_sql(stmt).fetchall()]
- @profiling.function_call_count(variance=0.10)
+ @profiling.function_call_count(variance=0.15)
def test_raw_unicode(self):
stmt = "SELECT %s FROM table2" % (
", ".join("field%d" % fnum for fnum in range(NUM_FIELDS))
diff --git a/test/dialect/postgresql/test_query.py b/test/dialect/postgresql/test_query.py
index 5ab65f9e3..eb96eaabb 100644
--- a/test/dialect/postgresql/test_query.py
+++ b/test/dialect/postgresql/test_query.py
@@ -609,8 +609,7 @@ class InsertTest(fixtures.TestBase, AssertsExecutionResults):
(exc.IntegrityError, exc.ProgrammingError),
conn.execute,
table.insert(),
- {"data": "d2"},
- {"data": "d3"},
+ [{"data": "d2"}, {"data": "d3"}],
)
with expect_warnings(
".*has no Python-side or server-side default.*"
@@ -628,14 +627,12 @@ class InsertTest(fixtures.TestBase, AssertsExecutionResults):
(exc.IntegrityError, exc.ProgrammingError),
conn.execute,
table.insert(),
- {"data": "d2"},
- {"data": "d3"},
+ [{"data": "d2"}, {"data": "d3"}],
)
conn.execute(
table.insert(),
- {"id": 31, "data": "d2"},
- {"id": 32, "data": "d3"},
+ [{"id": 31, "data": "d2"}, {"id": 32, "data": "d3"}],
)
conn.execute(table.insert(inline=True), {"id": 33, "data": "d4"})
eq_(
@@ -668,13 +665,11 @@ class InsertTest(fixtures.TestBase, AssertsExecutionResults):
(exc.IntegrityError, exc.ProgrammingError),
conn.execute,
table.insert(),
- {"data": "d2"},
- {"data": "d3"},
+ [{"data": "d2"}, {"data": "d3"}],
)
conn.execute(
table.insert(),
- {"id": 31, "data": "d2"},
- {"id": 32, "data": "d3"},
+ [{"id": 31, "data": "d2"}, {"id": 32, "data": "d3"}],
)
conn.execute(table.insert(inline=True), {"id": 33, "data": "d4"})
eq_(
diff --git a/test/engine/test_deprecations.py b/test/engine/test_deprecations.py
index f09f0f1e1..62bac312b 100644
--- a/test/engine/test_deprecations.py
+++ b/test/engine/test_deprecations.py
@@ -28,6 +28,7 @@ from sqlalchemy.testing import is_
from sqlalchemy.testing import is_false
from sqlalchemy.testing import is_instance_of
from sqlalchemy.testing import is_true
+from sqlalchemy.testing import mock
from sqlalchemy.testing.engines import testing_engine
from sqlalchemy.testing.mock import Mock
from sqlalchemy.testing.schema import Column
@@ -397,6 +398,25 @@ class DeprecatedEngineFeatureTest(fixtures.TablesTest):
with _string_deprecation_expect():
testing.db.execute(select1(testing.db)).scalar()
+ def test_execute_plain_string_events(self):
+
+ m1 = Mock()
+ select1_str = select1(testing.db)
+ with _string_deprecation_expect():
+ with testing.db.connect() as conn:
+ event.listen(conn, "before_execute", m1.before_execute)
+ event.listen(conn, "after_execute", m1.after_execute)
+ result = conn.execute(select1_str)
+ eq_(
+ m1.mock_calls,
+ [
+ mock.call.before_execute(mock.ANY, select1_str, [], {}, {}),
+ mock.call.after_execute(
+ mock.ANY, select1_str, [], {}, {}, result
+ ),
+ ],
+ )
+
def test_scalar_plain_string(self):
with _string_deprecation_expect():
testing.db.scalar(select1(testing.db))
@@ -772,6 +792,76 @@ class RawExecuteTest(fixtures.TablesTest):
]
+class DeprecatedExecParamsTest(fixtures.TablesTest):
+ __backend__ = True
+
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ "users",
+ metadata,
+ Column("user_id", INT, primary_key=True, autoincrement=False),
+ Column("user_name", VARCHAR(20)),
+ )
+
+ Table(
+ "users_autoinc",
+ metadata,
+ Column(
+ "user_id", INT, primary_key=True, test_needs_autoincrement=True
+ ),
+ Column("user_name", VARCHAR(20)),
+ )
+
+ def test_kwargs(self, connection):
+ users = self.tables.users
+
+ with testing.expect_deprecated_20(
+ r"The connection.execute\(\) method in "
+ "SQLAlchemy 2.0 will accept parameters as a single "
+ ):
+ connection.execute(
+ users.insert(), user_id=5, user_name="some name"
+ )
+
+ eq_(connection.execute(select(users)).all(), [(5, "some name")])
+
+ def test_positional_dicts(self, connection):
+ users = self.tables.users
+
+ with testing.expect_deprecated_20(
+ r"The connection.execute\(\) method in "
+ "SQLAlchemy 2.0 will accept parameters as a single "
+ ):
+ connection.execute(
+ users.insert(),
+ {"user_id": 5, "user_name": "some name"},
+ {"user_id": 6, "user_name": "some other name"},
+ )
+
+ eq_(
+ connection.execute(select(users).order_by(users.c.user_id)).all(),
+ [(5, "some name"), (6, "some other name")],
+ )
+
+ def test_single_scalar(self, connection):
+
+ users = self.tables.users_autoinc
+
+ with testing.expect_deprecated_20(
+ r"The connection.execute\(\) method in "
+ "SQLAlchemy 2.0 will accept parameters as a single "
+ ):
+ # TODO: I'm not even sure what this exec format is or how
+ # it worked if at all
+ connection.execute(users.insert(), "some name")
+
+ eq_(
+ connection.execute(select(users).order_by(users.c.user_id)).all(),
+ [(1, None)],
+ )
+
+
class EngineEventsTest(fixtures.TestBase):
__requires__ = ("ad_hoc_engines",)
__backend__ = True
diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py
index fd42224eb..5b922a97d 100644
--- a/test/engine/test_execute.py
+++ b/test/engine/test_execute.py
@@ -34,6 +34,7 @@ from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import config
from sqlalchemy.testing import engines
from sqlalchemy.testing import eq_
+from sqlalchemy.testing import expect_raises_message
from sqlalchemy.testing import expect_warnings
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
@@ -1420,6 +1421,18 @@ class EngineEventsTest(fixtures.TestBase):
eq_(canary.be1.call_count, 2)
eq_(canary.be2.call_count, 2)
+ def test_new_exec_driver_sql_no_events(self):
+ m1 = Mock()
+
+ def select1(db):
+ return str(select([1]).compile(dialect=db.dialect))
+
+ with testing.db.connect() as conn:
+ event.listen(conn, "before_execute", m1.before_execute)
+ event.listen(conn, "after_execute", m1.after_execute)
+ conn.exec_driver_sql(select1(testing.db))
+ eq_(m1.mock_calls, [])
+
def test_add_event_after_connect(self):
# new feature as of #2978
canary = Mock()
@@ -1504,6 +1517,83 @@ class EngineEventsTest(fixtures.TestBase):
[call(conn, ctx.cursor, stmt, ctx.parameters[0], ctx, False)],
)
+ @testing.combinations(
+ (
+ ([{"x": 5, "y": 10}, {"x": 8, "y": 9}],),
+ {},
+ [{"x": 5, "y": 10}, {"x": 8, "y": 9}],
+ {},
+ ),
+ ((), {"z": 10}, [], {"z": 10}, testing.requires.legacy_engine),
+ (({"z": 10},), {}, [], {"z": 10}),
+ )
+ def test_modify_parameters_from_event_one(
+ self, multiparams, params, expected_multiparams, expected_params
+ ):
+ # this is testing both the normalization added to parameters
+ # as of I97cb4d06adfcc6b889f10d01cc7775925cffb116 as well as
+ # that the return value from the event is taken as the new set
+ # of parameters.
+ def before_execute(
+ conn, clauseelement, multiparams, params, execution_options
+ ):
+ eq_(multiparams, expected_multiparams)
+ eq_(params, expected_params)
+ return clauseelement, (), {"q": "15"}
+
+ def after_execute(
+ conn, clauseelement, multiparams, params, result, execution_options
+ ):
+ eq_(multiparams, ())
+ eq_(params, {"q": "15"})
+
+ e1 = testing_engine(config.db_url)
+ event.listen(e1, "before_execute", before_execute, retval=True)
+ event.listen(e1, "after_execute", after_execute)
+
+ with e1.connect() as conn:
+ result = conn.execute(
+ select(bindparam("q", type_=String)), *multiparams, **params
+ )
+ eq_(result.all(), [("15",)])
+
+ @testing.provide_metadata
+ def test_modify_parameters_from_event_two(self, connection):
+ t = Table("t", self.metadata, Column("q", Integer))
+
+ t.create(connection)
+
+ def before_execute(
+ conn, clauseelement, multiparams, params, execution_options
+ ):
+ return clauseelement, [{"q": 15}, {"q": 19}], {}
+
+ event.listen(connection, "before_execute", before_execute, retval=True)
+ connection.execute(t.insert(), {"q": 12})
+ event.remove(connection, "before_execute", before_execute)
+
+ eq_(
+ connection.execute(select(t).order_by(t.c.q)).fetchall(),
+ [(15,), (19,)],
+ )
+
+ def test_modify_parameters_from_event_three(self, connection):
+ def before_execute(
+ conn, clauseelement, multiparams, params, execution_options
+ ):
+ return clauseelement, [{"q": 15}, {"q": 19}], {"q": 7}
+
+ e1 = testing_engine(config.db_url)
+ event.listen(e1, "before_execute", before_execute, retval=True)
+
+ with expect_raises_message(
+ tsa.exc.InvalidRequestError,
+ "Event handler can't return non-empty multiparams "
+ "and params at the same time",
+ ):
+ with e1.connect() as conn:
+ conn.execute(select(literal("1")))
+
def test_argument_format_execute(self):
def before_execute(
conn, clauseelement, multiparams, params, execution_options
@@ -1591,30 +1681,13 @@ class EngineEventsTest(fixtures.TestBase):
if ctx:
ctx.close()
- if engine._is_future:
- compiled = [
- ("CREATE TABLE t1", {}, None),
- (
- "INSERT INTO t1 (c1, c2)",
- {"c2": "some data", "c1": 5},
- None,
- ),
- ("INSERT INTO t1 (c1, c2)", {"c1": 6}, None),
- ("select * from t1", {}, None),
- ("DROP TABLE t1", {}, None),
- ]
- else:
- compiled = [
- ("CREATE TABLE t1", {}, None),
- (
- "INSERT INTO t1 (c1, c2)",
- {},
- ({"c2": "some data", "c1": 5},),
- ),
- ("INSERT INTO t1 (c1, c2)", {}, ({"c1": 6},)),
- ("select * from t1", {}, None),
- ("DROP TABLE t1", {}, None),
- ]
+ compiled = [
+ ("CREATE TABLE t1", {}, None),
+ ("INSERT INTO t1 (c1, c2)", {"c2": "some data", "c1": 5}, (),),
+ ("INSERT INTO t1 (c1, c2)", {"c1": 6}, ()),
+ ("select * from t1", {}, None),
+ ("DROP TABLE t1", {}, None),
+ ]
cursor = [
("CREATE TABLE t1", {}, ()),
diff --git a/test/engine/test_processors.py b/test/engine/test_processors.py
index 9bfd8d505..3810de06a 100644
--- a/test/engine/test_processors.py
+++ b/test/engine/test_processors.py
@@ -1,6 +1,7 @@
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import mock
class _BooleanProcessorTest(fixtures.TestBase):
@@ -107,70 +108,77 @@ class CDateProcessorTest(_DateProcessorTest):
class _DistillArgsTest(fixtures.TestBase):
def test_distill_none(self):
- eq_(self.module._distill_params(None, None), [])
+ eq_(self.module._distill_params(mock.Mock(), None, None), [])
def test_distill_no_multi_no_param(self):
- eq_(self.module._distill_params((), {}), [])
+ eq_(self.module._distill_params(mock.Mock(), (), {}), [])
def test_distill_dict_multi_none_param(self):
eq_(
- self.module._distill_params(None, {"foo": "bar"}), [{"foo": "bar"}]
+ self.module._distill_params(mock.Mock(), None, {"foo": "bar"}),
+ [{"foo": "bar"}],
)
def test_distill_dict_multi_empty_param(self):
- eq_(self.module._distill_params((), {"foo": "bar"}), [{"foo": "bar"}])
+ eq_(
+ self.module._distill_params(mock.Mock(), (), {"foo": "bar"}),
+ [{"foo": "bar"}],
+ )
def test_distill_single_dict(self):
eq_(
- self.module._distill_params(({"foo": "bar"},), {}),
+ self.module._distill_params(mock.Mock(), ({"foo": "bar"},), {}),
[{"foo": "bar"}],
)
def test_distill_single_list_strings(self):
eq_(
- self.module._distill_params((["foo", "bar"],), {}),
+ self.module._distill_params(mock.Mock(), (["foo", "bar"],), {}),
[["foo", "bar"]],
)
def test_distill_single_list_tuples(self):
eq_(
self.module._distill_params(
- ([("foo", "bar"), ("bat", "hoho")],), {}
+ mock.Mock(), ([("foo", "bar"), ("bat", "hoho")],), {}
),
[("foo", "bar"), ("bat", "hoho")],
)
def test_distill_single_list_tuple(self):
eq_(
- self.module._distill_params(([("foo", "bar")],), {}),
+ self.module._distill_params(mock.Mock(), ([("foo", "bar")],), {}),
[("foo", "bar")],
)
def test_distill_multi_list_tuple(self):
eq_(
self.module._distill_params(
- ([("foo", "bar")], [("bar", "bat")]), {}
+ mock.Mock(), ([("foo", "bar")], [("bar", "bat")]), {}
),
([("foo", "bar")], [("bar", "bat")]),
)
def test_distill_multi_strings(self):
- eq_(self.module._distill_params(("foo", "bar"), {}), [("foo", "bar")])
+ eq_(
+ self.module._distill_params(mock.Mock(), ("foo", "bar"), {}),
+ [("foo", "bar")],
+ )
def test_distill_single_list_dicts(self):
eq_(
self.module._distill_params(
- ([{"foo": "bar"}, {"foo": "hoho"}],), {}
+ mock.Mock(), ([{"foo": "bar"}, {"foo": "hoho"}],), {}
),
[{"foo": "bar"}, {"foo": "hoho"}],
)
def test_distill_single_string(self):
- eq_(self.module._distill_params(("arg",), {}), [["arg"]])
+ eq_(self.module._distill_params(mock.Mock(), ("arg",), {}), [["arg"]])
def test_distill_multi_string_tuple(self):
eq_(
- self.module._distill_params((("arg", "arg"),), {}),
+ self.module._distill_params(mock.Mock(), (("arg", "arg"),), {}),
[("arg", "arg")],
)
diff --git a/test/profiles.txt b/test/profiles.txt
index f2aaeb073..19db8b148 100644
--- a/test/profiles.txt
+++ b/test/profiles.txt
@@ -1,15 +1,15 @@
# /home/classic/dev/sqlalchemy/test/profiles.txt
# This file is written out on a per-environment basis.
-# For each test in aaa_profiling, the corresponding function and
+# For each test in aaa_profiling, the corresponding function and
# environment is located within this file. If it doesn't exist,
# the test is skipped.
-# If a callcount does exist, it is compared to what we received.
+# If a callcount does exist, it is compared to what we received.
# assertions are raised if the counts do not match.
-#
-# To add a new callcount test, apply the function_call_count
-# decorator and re-run the tests using the --write-profiles
+#
+# To add a new callcount test, apply the function_call_count
+# decorator and re-run the tests using the --write-profiles
# option - this file will be rewritten including the new count.
-#
+#
# TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert
@@ -394,6 +394,7 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 51
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 49
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51
+test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 54
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 53
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 53
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 53
@@ -421,6 +422,7 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 91
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 89
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 91
+test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 92
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 91
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 91
test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 91
@@ -448,6 +450,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86
test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 16
test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 16
test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 16
+test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 17
test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 17
test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 17
test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 17
@@ -475,6 +478,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 13507
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 1458
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 13460
+test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 1547
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 1509
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 13512
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_legacy x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 1516
@@ -502,6 +506,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_6
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 15512
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 2465
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 15467
+test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 2553
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 2517
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 15520
test.aaa_profiling.test_resultset.ResultSetTest.test_fetch_by_key_mappings x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 2524
@@ -529,6 +534,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 14
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 14
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 14
+test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 23
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 15
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 15
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-0] x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 23
@@ -556,6 +562,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 16
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 14
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 16
+test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 23
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 15
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 17
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-1] x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 23
@@ -583,6 +590,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 16
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 14
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 16
+test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 23
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 15
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 17
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[False-2] x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 23
@@ -610,6 +618,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 19
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 17
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 19
+test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 28
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 18
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 20
test.aaa_profiling.test_resultset.ResultSetTest.test_one_or_none[True-1] x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 28
@@ -637,6 +646,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpy
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6302
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 251
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6271
+test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 263
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 256
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 6256
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 288
@@ -647,7 +657,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpy
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_nocextensions 6345
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 278
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 6278
-test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 245
+test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 222
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_string x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_nocextensions 6245
# TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode
@@ -664,6 +674,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cp
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6302
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 251
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6271
+test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 263
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 256
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 6256
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 288
@@ -674,7 +685,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cp
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_nocextensions 6345
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 278
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 6278
-test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 245
+test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 222
test.aaa_profiling.test_resultset.ResultSetTest.test_raw_unicode x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_nocextensions 6245
# TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_string
@@ -691,6 +702,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython
test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6505
test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 458
test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6460
+test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 548
test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 521
test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 6521
test.aaa_profiling.test_resultset.ResultSetTest.test_string x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 528
@@ -718,6 +730,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpytho
test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6505
test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 458
test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6460
+test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 548
test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 521
test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 6521
test.aaa_profiling.test_resultset.ResultSetTest.test_unicode x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 528