The "expanding IN" feature, which generates IN expressions at query
execution time which are based on the particular parameters associated with
the statement execution, is now used for all IN expressions made against
lists of literal values. This allows IN expressions to be fully cacheable
independently of the list of values being passed, and also includes support
for empty lists. For any scenario where the IN expression contains
non-literal SQL expressions, the old behavior of pre-rendering for each
position in the IN is maintained. The change also completes support for
expanding IN with tuples, where previously type-specific bind processors
weren't taking effect.
As part of this change, a more explicit separation between
"literal execute" and "post compile" bound parameters is being made;
as the "ansi bind rules" feature is rendering bound parameters
inline, as we now support "postcompile" generically, these should
be used here, however we have to render literal values at
execution time even for "expanding" parameters. new test fixtures
etc. are added to assert everything goes to the right place.
Fixes: #4645
Change-Id: Iaa2b7bfbfaaf5b80799ee17c9b8507293cba6ed1
Fixed issue where the collection of value processors on a
:class:`.Compiled` object would be mutated when "expanding IN" parameters
were used with a datatype that has bind value processors; in particular,
this would mean that when using statement caching and/or baked queries, the
same compiled._bind_processors collection would be mutated concurrently.
Since these processors are the same function for a given bind parameter
namespace every time, there was no actual negative effect of this issue,
however, the execution of a :class:`.Compiled` object should never be
causing any changes in its state, especially given that they are intended
to be thread-safe and reusable once fully constructed.
Fixes: #5048
Change-Id: I876d16bd7484eb05ce590397420552ac36da6e52
As part of the SQLAlchemy 2.0 migration project, a conceptual change has
been made to the role of the :class:`.SelectBase` class hierarchy,
which is the root of all "SELECT" statement constructs, in that they no
longer serve directly as FROM clauses, that is, they no longer subclass
:class:`.FromClause`. For end users, the change mostly means that any
placement of a :func:`.select` construct in the FROM clause of another
:func:`.select` requires first that it be wrapped in a subquery first,
which historically is through the use of the :meth:`.SelectBase.alias`
method, and is now also available through the use of
:meth:`.SelectBase.subquery`. This was usually a requirement in any
case since several databases don't accept unnamed SELECT subqueries
in their FROM clause in any case.
See the documentation in this change for lots more detail.
Fixes: #4617
Change-Id: I0f6174ee24b9a1a4529168e52e855e12abd60667
Applied on top of a pure run of black -l 79 in
I7eda77fed3d8e73df84b3651fd6cfcfe858d4dc9, this set of changes
resolves all remaining flake8 conditions for those codes
we have enabled in setup.cfg.
Included are resolutions for all remaining flake8 issues
including shadowed builtins, long lines, import order, unused
imports, duplicate imports, and docstring issues.
Change-Id: I4f72d3ba1380dd601610ff80b8fb06a2aff8b0fe
This is a straight reformat run using black as is, with no edits
applied at all.
The black run will format code consistently, however in
some cases that are prevalent in SQLAlchemy code it produces
too-long lines. The too-long lines will be resolved in the
following commit that will resolve all remaining flake8 issues
including shadowed builtins, long lines, import order, unused
imports, duplicate imports, and docstring issues.
Change-Id: I7eda77fed3d8e73df84b3651fd6cfcfe858d4dc9
Fixed issue in "expanding IN" feature where using the same bound parameter
name more than once in a query would lead to a KeyError within the process
of rewriting the parameters in the query.
Fixes: #4394
Change-Id: Ibcadce9fefbcb060266d9447c2044ee6efeccf5a
MariaDB seems to handle some additional UPDATE/DELETE FROM
syntaxes as well as some forms of INTERSECT and EXCEPT. Open
up tests that expect failure for MySQL to allow success for
MariaDB 10.3.
Change-Id: Ia9341a82485ef7201bb8130d8dbf4a9b6976035a
Added new logic to the "expanding IN" bound parameter feature whereby if
the given list is empty, a special "empty set" expression that is specific
to different backends is generated, thus allowing IN expressions to be
fully dynamic including empty IN expressions.
Fixes: #4271
Change-Id: Icc3c73bbd6005206b9d06baaeb14a097af5edd36
Pull-request: https://github.com/zzzeek/sqlalchemy/pull/432
Fixed bug in new "expanding bind parameter" feature whereby if multiple
params were used in one statement, the regular expression would not
match the parameter name correctly.
Change-Id: Ifaf7d627aac4ead2a13c8dddccb5c515253d88e6
Fixes: #4140
Added a new kind of :func:`.bindparam` called "expanding". This is
for use in ``IN`` expressions where the list of elements is rendered
into individual bound parameters at statement execution time, rather
than at statement compilation time. This allows both a single bound
parameter name to be linked to an IN expression of multiple elements,
as well as allows query caching to be used with IN expressions. The
new feature allows the related features of "select in" loading and
"polymorphic in" loading to make use of the baked query extension
to reduce call overhead. This feature should be considered to be
**experimental** for 1.2.
Fixes: #3953
Change-Id: Ie708414a3ab9c0af29998a2c7f239ff7633b1f6e
The longstanding behavior of the :meth:`.Operators.in_` and
:meth:`.Operators.not_in_` operators emitting a warning when
the right-hand condition is an empty sequence has been revised;
a new flag :paramref:`.create_engine.empty_in_strategy` allows an
empty "IN" expression to generate a simple boolean expression, or
to invoke the previous behavior of dis-equating the expression to
itself, with or without a warning. The default behavior is now
to emit the simple boolean expression, allowing an empty IN to
be evaulated without any performance penalty.
Change-Id: I65cc37f2d7cf65a59bf217136c42fee446929352
Fixes: #3907
Corrects some warnings and adds tox config. Adds DeprecationWarning
to the error category. Large sweep for string literals w/ backslashes
as this is common in docstrings
Co-authored-by: Andrii Soldatenko
Fixes: #3886
Change-Id: Ia7c838dfbbe70b262622ed0803d581edc736e085
Pull-request: https://github.com/zzzeek/sqlalchemy/pull/337
by the ORM :class:`.Query` object (part of the performance
enhancements of 🎫`3175`) would not raise the "this result
does not return rows" exception in the case where the driver
(typically MySQL) fails to generate cursor.description correctly;
an AttributeError against NoneType would be raised instead.
fixes#3481
un-adjusted internal symbol names for "anonymous" labels, which
are the "foo_1" types of labels we see generated for SQL functions
without labels and similar. This was a side effect of the
performance enhancements implemented as part of references #918.
fixes#3483
for an insert from select are the string names, and not
the Column objects. The MSSQL dialect in particular relies upon
checking for these keys in params to know if identity insert
should be on. references #3360
That is, after exhausing all rows using the fetch methods, the
DBAPI cursor is released as before and the object may be safely
discarded, but the fetch methods may continue to be called for which
they will return an end-of-result object (None for fetchone, empty list
for fetchmany and fetchall). Only if :meth:`.ResultProxy.close`
is called explicitly will these methods raise the "result is closed"
error.
fixes#3330fixes#3329
such that they are matched to the received result set positionally,
rather than by name. Originally, this was seen as a way to handle
cases where we had columns returned with difficult-to-predict names,
though in modern use that issue has been overcome by anonymous
labeling. In this version, the approach basically reduces function
call count per-result by a few dozen calls, or more for larger
sets of result columns. The approach still degrades into a modern
version of the old approach if textual elements modify the result
map, or if any discrepancy in size exists between
the compiled set of columns versus what was received, so there's no
issue for partially or fully textual compilation scenarios where these
lists might not line up. fixes#918
- callcounts still need to be adjusted down for this so zoomark
tests won't pass at the moment
and parameters are not displayed if None, reducing confusion for
error messages that weren't related to a statement. The full
module and classname for the DBAPI-level exception is displayed,
making it clear that this is a wrapped DBAPI exception. The
statement and parameters themselves are bounded within a bracketed
sections to better isolate them from the error message and from
each other.
fixes#3172
the python 3 merge, now does not expect percent signs (e.g.
as used as the modulus operator and others) to be doubled,
even when using the "pyformat" bound parameter format (this
change is not documented by Mysqlconnector). The dialect now
checks for py2k and for mysqlconnector less than version 2.0
when detecting if the modulus operator should be rendered as
``%%`` or ``%``.
- Unicode SQL is now passed for MySQLconnector version 2.0 and above;
for Py2k and MySQL < 2.0, strings are encoded. Note that mysqlconnector
as of 2.0.1 appears to have a bug with unicode DDL on py2k, so the tests here
are skipping until we observe it's fixed.
- take out profiling on mysqlconnector, callcounts vary too much with
its current development speed
constructs are now importable from the "from sqlalchemy" namespace,
just like every other Core construct.
- The implicit conversion of strings to :func:`.text` constructs
when passed to most builder methods of :func:`.select` as
well as :class:`.Query` now emits a warning with just the
plain string sent. The textual conversion still proceeds normally,
however. The only method that accepts a string without a warning
are the "label reference" methods like order_by(), group_by();
these functions will now at compile time attempt to resolve a single
string argument to a column or label expression present in the
selectable; if none is located, the expression still renders, but
you get the warning again. The rationale here is that the implicit
conversion from string to text is more unexpected than not these days,
and it is better that the user send more direction to the Core / ORM
when passing a raw string as to what direction should be taken.
Core/ORM tutorials have been updated to go more in depth as to how text
is handled.
fixes#2992
on :class:`.Insert`. This helps to fix a bug where an
INSERT...FROM SELECT construct would inadvertently be compiled
as "implicit returning" on supporting backends, which would
cause breakage in the case of an INSERT that inserts zero rows
(as implicit returning expects a row), as well as arbitrary
return data in the case of an INSERT that inserts multiple
rows (e.g. only the first row of many).
A similar change is also applied to an INSERT..VALUES
with multiple parameter sets; implicit RETURNING will no longer emit
for this statement either. As both of these constructs deal
with varible numbers of rows, the
:attr:`.ResultProxy.inserted_primary_key` accessor does not
apply. Previously, there was a documentation note that one
may prefer ``inline=True`` with INSERT..FROM SELECT as some databases
don't support returning and therefore can't do "implicit" returning,
but there's no reason an INSERT...FROM SELECT needs implicit returning
in any case. Regular explicit :meth:`.Insert.returning` should
be used to return variable numbers of result rows if inserted
data is needed.
fixes#3169
is currently being supported in addition to nose, and will likely
be preferred to nose going forward. The nose plugin system used
by SQLAlchemy has been split out so that it works under pytest as
well. There are no plans to drop support for nose at the moment
and we hope that the test suite itself can continue to remain as
agnostic of testing platform as possible. See the file
README.unittests.rst for updated information on running tests
with pytest.
The test plugin system has also been enhanced to support running
tests against mutiple database URLs at once, by specifying the ``--db``
and/or ``--dburi`` flags multiple times. This does not run the entire test
suite for each database, but instead allows test cases that are specific
to certain backends make use of that backend as the test is run.
When using pytest as the test runner, the system will also run
specific test suites multiple times, once for each database, particularly
those tests within the "dialect suite". The plan is that the enhanced
system will also be used by Alembic, and allow Alembic to run
migration operation tests against multiple backends in one run, including
third-party backends not included within Alembic itself.
Third party dialects and extensions are also encouraged to standardize
on SQLAlchemy's test suite as a basis; see the file README.dialects.rst
for background on building out from SQLAlchemy's test platform.
using a column key of the form ``<tablename>_<columnname>``
matching that of an aliased column in the text would still not
match at the ORM level, which is ultimately due to a core
column-matching issue. Additional rules have been added so that the
column ``_label`` is taken into account when working with a
:class:`.TextAsFrom` construct or with literal columns.
[ticket:2932]
oriented row lookups were not matching up to the ad-hoc :class:`.ColumnClause`
objects that :class:`.TextAsFrom` generates, thereby making it not
usable as a target in :meth:`.Query.from_statement`. Also fixed
:meth:`.Query.from_statement` mechanics to not mistake a :class:`.TextAsFrom`
for a :class:`.Select` construct. This bug is also an 0.9 regression
as the :meth:`.Text.columns` method is called to accommodate the
:paramref:`.text.typemap` argument. [ticket:2932]
would lead to ``TypeError`` when compared to non-tuple types as it attempted
to apply tuple() to the "other" object unconditionally. The
full range of Python comparison operators have now been implemented on
:class:`.RowProxy`, using an approach that guarantees a comparison
system that is equivalent to that of a tuple, and the "other" object
is only coerced if it's an instance of RowProxy. [ticket:2924]
when a pre-DBAPI :class:`.StatementError` were raised within
:meth:`.Connection.execute`, causing encoding errors for
non-ASCII statements. The stringification now remains within
Python unicode thus avoiding encoding errors. [ticket:2871]
tuple is; this is accomplished via ensuring tuple() conversion on
both sides within the ``__eq__()`` method as well as
the addition of a ``__lt__()`` method. [ticket:2848]
labeled columns when apply_labels() is used; this mode
produces a SELECT where each column is labeled as in
<tablename>_<columnname>, to remove column name collisions
for a multiple table select. The fix is that if two labels
collide when combined with the table name, i.e.
"foo.bar_id" and "foo_bar.id", anonymous aliasing will be
applied to one of the dupes. This allows the ORM to handle
both columns independently; previously, 0.7
would in some cases silently emit a second SELECT for the
column that was "duped", and in 0.8 an ambiguous column error
would be emitted. The "keys" applied to the .c. collection
of the select() will also be deduped, so that the "column
being replaced" warning will no longer emit for any select()
that specifies use_labels, though the dupe key will be given
an anonymous label which isn't generally user-friendly.
[ticket:2702]