diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-12-09 18:05:00 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-12-22 11:31:13 -0500 |
commit | 60e7034a7423955cd89d5624f8769d3804ca6d82 (patch) | |
tree | 027fd963fc073970b9ab62ae7f389e61192b1992 /lib/sqlalchemy/sql/operators.py | |
parent | c6554ac52bfb7ce9ecd30ec777ce90adfe7861d2 (diff) | |
download | sqlalchemy-60e7034a7423955cd89d5624f8769d3804ca6d82.tar.gz |
Use expanding IN for all literal value IN expressions
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
Diffstat (limited to 'lib/sqlalchemy/sql/operators.py')
-rw-r--r-- | lib/sqlalchemy/sql/operators.py | 28 |
1 files changed, 7 insertions, 21 deletions
diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index 3aeaaa601..22bf3d150 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -538,17 +538,15 @@ class ColumnOperators(Operators): stmt.where(column.in_([])) - In this calling form, the expression renders a "false" expression, - e.g.:: + In this calling form, the expression renders an "empty set" + expression. These expressions are tailored to individual backends + and are generaly trying to get an empty SELECT statement as a + subuqery. Such as on SQLite, the expression is:: - WHERE 1 != 1 + WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1) - This "false" expression has historically had different behaviors - in older SQLAlchemy versions, see - :paramref:`.create_engine.empty_in_strategy` for behavioral options. - - .. versionchanged:: 1.2 simplified the behavior of "empty in" - expressions + .. versionchanged:: 1.4 empty IN expressions now use an + execution-time generated SELECT subquery in all cases. * A bound parameter, e.g. :func:`.bindparam`, may be used if it includes the :paramref:`.bindparam.expanding` flag:: @@ -1341,16 +1339,6 @@ def comma_op(a, b): raise NotImplementedError() -@comparison_op -def empty_in_op(a, b): - raise NotImplementedError() - - -@comparison_op -def empty_notin_op(a, b): - raise NotImplementedError() - - def filter_op(a, b): raise NotImplementedError() @@ -1473,8 +1461,6 @@ _PRECEDENCE = { ne: 5, is_distinct_from: 5, isnot_distinct_from: 5, - empty_in_op: 5, - empty_notin_op: 5, gt: 5, lt: 5, ge: 5, |