Commit Graph

102 Commits

Author SHA1 Message Date
Federico Caselli 0620473085 Improve handling of sentinel columns
Fixed issue in "insertmanyvalues" feature where an INSERT..RETURNING 
that also made use of a sentinel column to track results would fail to 
filter out the additional column when :meth:`.Result.unique` were used 
to uniquify the result set.
    
Fixes: #10802
Change-Id: Ie4f9dab96193099002088c5219cc41a543a00f62
2025-07-14 19:28:00 +00:00
Federico Caselli 2adc79c077 Removed support for Python 3.8 since it's EOL.
Fixes: #12029
Change-Id: Ibb4efec9bab0225d03f6bf3fed661a3f2fc72cc7
2024-11-05 21:23:34 +01:00
Mike Bayer fbb7172c69 ensure result_map objects collection is non-empty
Fixed issue in cursor handling which affected handling of duplicate
:class:`_sql.Column` or similar objcts in the columns clause of
:func:`_sql.select`, both in combination with arbitary :func:`_sql.text()`
clauses in the SELECT list, as well as when attempting to retrieve
:meth:`_engine.Result.mappings` for the object, which would lead to an
internal error.

Fixes: #11306
Change-Id: I418073b2fdba86b2121b6d00eaa40b1805b69bb8
2024-04-30 15:49:36 -04:00
Federico Caselli b5cf61c504 Fix missing pythonpath in test that use subprocess
Ensure the ``PYTHONPATH`` variable is properly initialized when
using ``subprocess.run`` in the tests.

Fixes: #11268
Change-Id: Ie2db656364931b3be9033dcaaf7a7c56b383ecca
2024-04-15 21:52:38 +02:00
Federico Caselli f0537442eb Add support for preserve_rowcount execution_option
Added new core execution option
paramref:`_engine.Connection.execution_options.preserve_rowcount`
to unconditionally save the ``rowcount`` attribute from the cursor in the
class:`_engine.Result` returned from an execution, regardless of the
statement being executed.
When this option is provided the correct value is also set when
an INSERT makes use of the "insertmanyvalues" mode, that may use
more than one actualy cursor execution.

Fixes: #10974
Change-Id: Icecef6b7539be9f0a1a02b9539864f5f163dcfbc
2024-03-03 17:58:12 -05:00
Federico Caselli 3fbbe8d67b remove unnecessary string concat in same line
manually update the files to remove literal string concat on the same line,
since black does not seem to be making progress in handling these

Change-Id: I3c651374c5f3db5b8bc0c700328d67ca03743b7b
2024-02-06 19:44:47 +01:00
Federico Caselli 9b153ff18f Update black to 24.1.1
Change-Id: Iadaea7b798d8e99302e1acb430dc7b758ca61137
2024-01-31 21:54:59 +01:00
Yurii Karabas 00072000c5 Add PEP 646 integration
The :class:`.Row` object now no longer makes use of an intermediary
``Tuple`` in order to represent its individual element types; instead,
the individual element types are present directly, via new :pep:`646`
integration, now available in more recent versions of Mypy.  Mypy
1.7 or greater is now required for statements, results and rows
to be correctly typed.   Pull request courtesy Yurii Karabas.

Fixes: #10635
Closes: #10634
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10634
Pull-request-sha: 430785c8a0

Change-Id: Ibd0ae31a98b4ea69dcb89f970e640920b2be6c48
2024-01-22 19:49:05 +01:00
Federico Caselli 4da59c6f53 More python 3.7 removal cleanups
Change-Id: I6de7754361c649af323fa1a90fe29371c98b1541
2023-11-07 19:21:06 +01:00
Federico Caselli ed1e2f4b34 Rename Row t and tuples with underscored versions.
Renamed :attr:`_result.Row.t` and :meth:`_result.Row.tuple` to
:attr:`_result.Row._t` and :meth:`_result.Row._tuple`; this is to suit the
policy that all methods and pre-defined attributes on :class:`.Row` should
be in the style of Python standard library ``namedtuple`` where all fixed
names have a leading underscore, to avoid name conflicts with existing
column names.   The previous method/attribute is now deprecated and will
emit a deprecation warning.

Fixes: #10093
Change-Id: Ibb0e9423b55590c9dda8ee554187abd9a9122590
2023-07-14 14:32:59 -04:00
J. Nick Koston ff198e35f0 Prebuild the row string to position lookup for Rows
Improved :class:`_engine.Row` implementation to optimize
``__getattr__`` performance.
The serialization of a :class:`_engine.Row` to pickle has changed with
this change. Pickle saved by older SQLAlchemy versions can still be loaded,
but new pickle saved by this version cannot be loaded by older ones.

Fixes: #9678
Closes: #9668
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/9668
Pull-request-sha: 86b8ccd195

Change-Id: Ia85c26a59e1a57ba2bf0d65578c6168f82a559f2
2023-04-26 20:19:17 +02:00
Andy Freeland c1125288e3 Fix RowMapping's Mapping type to reflect that it supports Columns or strings
### Description

I ran into this originally in sqlalchemy2-stubs: https://github.com/sqlalchemy/sqlalchemy2-stubs/pull/251, where `RowMapping` only supported string keys according to the type hints. I ran into a similar issue here upgrading our application where because `RowMapping` subclassed `Mapping[str, Any]`, `Row._mapping.get()` would fail to typecheck when used with `Column` objects.

This patch adds a test to verify that `Row._mapping.get()` continues to work with both strings and `Column`s, though it doesn't look like mypy checks types in the tests.

Fixes #9644.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical error fix
	- Good to go, no issue or tests are needed
- [x] A short code fix
	- please include the issue number, and create an issue if none exists, which
	  must include a complete example of the issue.  one line code fixes without an
	  issue and demonstration will not be accepted.
	- Please include: `Fixes: #<issue number>` in the commit message
	- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
	- please include the issue number, and create an issue if none exists, which must
	  include a complete example of how the feature would look.
	- Please include: `Fixes: #<issue number>` in the commit message
	- please include tests.

**Have a nice day!**

Closes: #9643
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/9643
Pull-request-sha: 6c33fe534c

Change-Id: I1009c6defff109d73f13a9e8c51641009e6a79e2
2023-04-20 20:55:21 +02:00
Federico Caselli fd9aa84792 Fix regression when deserializing python rows into cython
Fixed regression involving pickling of Python rows between the cython and
pure Python implementations of :class:`.Row`, which occurred as part of
refactoring code for version 2.0 with typing. A particular constant were
turned into a string based ``Enum`` for the pure Python version of
:class:`.Row` whereas the cython version continued to use an integer
constant, leading to deserialization failures.

Regression occurred in a4bb502cf9

Fixes: #9423
Change-Id: Icbd85cacb2d589cef7c246de7064249926146f2e
2023-03-10 10:26:26 -05:00
Mike Bayer 3711179587 comment out pickle/ process test and attempt 2.0.5.post1
if .post1 fails to work out, we'll just do 2.0.6

The test_pickle_rows_other_process test is failing during wheel
builds as it seems that the "subprocess" run is not using the
cython extensions, leading to a pickle mismatch between the
cythonized and the pure python version of a row.  comment
out this test and attempt to release as 2.0.5.post1 so that
wheels can build.

Fixes: #9429
Change-Id: I6e1e9f2b9c4ef8fa67a88ff86ebdacbeb02b90df
2023-03-05 22:25:46 -05:00
mike bayer a7d403166c Merge "Fixed bug where :meth:_engine.Rows could not be unpickled by other processes." into main 2023-03-05 20:33:46 +00:00
Mike Bayer b38fb59fe4 audition pymssql once more; retire sane_rowcount_returning
pymssql seems to be maintained again and seems to be working
completely, so let's try re-enabling it.

Fixed issue in the new :class:`.Uuid` datatype which prevented it from
working with the pymssql driver. As pymssql seems to be maintained again,
restored testing support for pymssql.

Tweaked the pymssql dialect to take better advantage of
RETURNING for INSERT statements in order to retrieve last inserted primary
key values, in the same way as occurs for the mssql+pyodbc dialect right
now.

Identified that the ``sqlite`` and ``mssql+pyodbc`` dialects are now
compatible with the SQLAlchemy ORM's "versioned rows" feature, since
SQLAlchemy now computes rowcount for a RETURNING statement in this specific
case by counting the rows returned, rather than relying upon
``cursor.rowcount``.  In particular, the ORM versioned rows use case
(documented at :ref:`mapper_version_counter`) should now be fully
supported with the SQL Server pyodbc dialect.

Change-Id: I38a0666587212327aecf8f98e86031ab25d1f14d
References: #5321
Fixes: #9414
2023-03-04 23:22:20 -05:00
Federico Caselli 4dc2ce0fb1 Fixed bug where :meth:_engine.Rows could not be
unpickled by other processes.

Fixes: #9423
Change-Id: Ie496e31158caff5f72e0a9069dddd55f3116e0b8
2023-03-04 23:33:02 +01:00
Mike Bayer 44170aee47 look out for extras=None in freeze
Fixed issue where :meth:`_engine.Result.freeze` method would not work for
textual SQL using either :func:`_sql.text` or
:meth:`_engine.Connection.exec_driver_sql`.

Fixes: #8963
Change-Id: Ia131c6ac41a4adf32eb1bf1abf23930ef395f16c
2022-12-09 15:56:15 -05:00
Federico Caselli 06c234d037 Rewrite positional handling, test for "numeric"
Changed how the positional compilation is performed. It's rendered by the compiler
the same as the pyformat compilation. The string is then processed to replace
the placeholders with the correct ones, and to obtain the correct order of the
parameters.
This vastly simplifies the computation of the order of the parameters, that in
case of nested CTE is very hard to compute correctly.

Reworked how numeric paramstyle behavers:
- added support for repeated parameter, without duplicating them like in normal
positional dialects
- implement insertmany support. This requires that the dialect supports out of
order placehoders, since all parameters that are not part of the VALUES clauses
are placed at the beginning of the parameter tuple
- support for different identifiers for a numeric parameter. It's for example
possible to use postgresql style placeholder $1, $2, etc

Added two new dialect based on sqlite to test "numeric" fully using
both :1 style and $1 style. Includes a workaround for SQLite's
not-really-correct numeric implementation.

Changed parmstyle of asyncpg dialect to use numeric, rendering with its native
$ identifiers

Fixes: #8926
Fixes: #8849
Change-Id: I7c640467d49adfe6d795cc84296fc7403dcad4d6
2022-12-05 09:59:01 -05:00
Federico Caselli 4eb4ceca36 Try running pyupgrade on the code
command run is "pyupgrade --py37-plus --keep-runtime-typing --keep-percent-format <files...>"
pyupgrade will change assert_ to assertTrue. That was reverted since assertTrue does not
exists in sqlalchemy fixtures

Change-Id: Ie1ed2675c7b11d893d78e028aad0d1576baebb55
2022-11-16 23:03:04 +01:00
Mike Bayer b96321ae79 Support result.close() for all iterator patterns
This change contains new features for 2.0 only as well as some
behaviors that will be backported to 1.4.

For 1.4 and 2.0:

Fixed issue where the underlying DBAPI cursor would not be closed when
using :class:`_orm.Query` with :meth:`_orm.Query.yield_per` and direct
iteration, if a user-defined exception case were raised within the
iteration process, interrupting the iterator. This would lead to the usual
MySQL-related issues with server side cursors out of sync.

For 1.4 only:

A similar scenario can occur when using :term:`2.x` executions with direct
use of :class:`.Result`, in that case the end-user code has access to the
:class:`.Result` itself and should call :meth:`.Result.close` directly.
Version 2.0 will feature context-manager calling patterns to address this
use case.  However within the 1.4 scope, ensured that ``.close()`` methods
are available on all :class:`.Result` implementations including
:class:`.ScalarResult`, :class:`.MappingResult`.

For 2.0 only:

To better support the use case of iterating :class:`.Result` and
:class:`.AsyncResult` objects where user-defined exceptions may interrupt
the iteration, both objects as well as variants such as
:class:`.ScalarResult`, :class:`.MappingResult`,
:class:`.AsyncScalarResult`, :class:`.AsyncMappingResult` now support
context manager usage, where the result will be closed at the end of
iteration.

Corrected various typing issues within the engine and async engine
packages.

Fixes: #8710
Change-Id: I3166328bfd3900957eb33cbf1061d0495c9df670
2022-11-03 18:42:52 -04:00
Mike Bayer a8029f5a7e ORM bulk insert via execute
* ORM Insert now includes "bulk" mode that will run
  essentially the same process as session.bulk_insert_mappings;
  interprets the given list of values as ORM attributes for
  key names
* ORM UPDATE has a similar feature, without RETURNING support,
  for session.bulk_update_mappings
* Added support for upserts to do RETURNING ORM objects as well
* ORM UPDATE/DELETE with list of parameters + WHERE criteria
  is a not implemented; use connection
* ORM UPDATE/DELETE defaults to "auto" synchronize_session;
  use fetch if RETURNING is present, evaluate if not, as
  "fetch" is much more efficient (no expired object SELECT problem)
  and less error prone if RETURNING is available
  UPDATE: howver this is inefficient!   please continue to
  use evaluate for simple cases, auto can move to fetch
  if criteria not evaluable
* "Evaluate" criteria will now not preemptively
  unexpire and SELECT attributes that were individually
  expired. Instead, if evaluation of the criteria indicates that
  the necessary attrs were expired, we expire the object
  completely (delete) or expire the SET attrs unconditionally
  (update). This keeps the object in the same unloaded state
  where it will refresh those attrs on the next pass, for
  this generally unusual case.  (originally #5664)
* Core change! update/delete rowcount comes from len(rows)
  if RETURNING was used.  SQLite at least otherwise did not
  support this.  adjusted test_rowcount accordingly
* ORM DELETE with a list of parameters at all is also a not
  implemented as this would imply "bulk", and there is no
  bulk_delete_mappings (could be, but we dont have that)
* ORM insert().values() with single or multi-values translates
  key names based on ORM attribute names
* ORM returning() implemented for insert, update, delete;
  explcit returning clauses now interpret rows in an ORM
  context, with support for qualifying loader options as well
* session.bulk_insert_mappings() assigns polymorphic identity
  if not set.
* explicit RETURNING + synchronize_session='fetch' is now
  supported with UPDATE and DELETE.
* expanded return_defaults() to work with DELETE also.
* added support for composite attributes to be present
  in the dictionaries used by bulk_insert_mappings and
  bulk_update_mappings, which is also the new ORM bulk
  insert/update feature, that will expand the composite
  values into their individual mapped attributes the way they'd
  be on a mapped instance.
* bulk UPDATE supports "synchronize_session=evaluate", is the
  default.  this does not apply to session.bulk_update_mappings,
  just the new version
* both bulk UPDATE and bulk INSERT, the latter with or without
  RETURNING, support *heterogenous* parameter sets.
  session.bulk_insert/update_mappings did this, so this feature
  is maintained.  now cursor result can be both horizontally
  and vertically spliced :)

This is now a long story with a lot of options, which in
itself is a problem to be able to document all of this
in some way that makes sense.  raising exceptions for
use cases we haven't supported is pretty important here
too, the tradition of letting unsupported things just not work
is likely not a good idea at this point, though there
are still many cases that aren't easily avoidable

Fixes: #8360
Fixes: #7864
Fixes: #7865
Change-Id: Idf28379f8705e403a3c6a937f6a798a042ef2540
2022-09-24 11:18:01 -04:00
Mike Bayer c9af2ebf5e break out text() from TextualSelect for col matching
Fixed issue where mixing "*" with additional explicitly-named column
expressions within the columns clause of a :func:`_sql.select` construct
would cause result-column targeting to sometimes consider the label name or
other non-repeated names to be an ambiguous target.

Fixes: #8536
Change-Id: I3c845eaf571033e54c9208762344f67f4351ac3a
2022-09-19 18:39:18 -04:00
Mike Bayer 741af02893 repair yield_per for non-SS dialects and add new options
Implemented new :paramref:`_engine.Connection.execution_options.yield_per`
execution option for :class:`_engine.Connection` in Core, to mirror that of
the same :ref:`yield_per <orm_queryguide_yield_per>` option available in
the ORM. The option sets both the
:paramref:`_engine.Connection.execution_options.stream_results` option at
the same time as invoking :meth:`_engine.Result.yield_per`, to provide the
most common streaming result configuration which also mirrors that of the
ORM use case in its usage pattern.

Fixed bug in :class:`_engine.Result` where the usage of a buffered result
strategy would not be used if the dialect in use did not support an
explicit "server side cursor" setting, when using
:paramref:`_engine.Connection.execution_options.stream_results`. This is in
error as DBAPIs such as that of SQLite and Oracle already use a
non-buffered result fetching scheme, which still benefits from usage of
partial result fetching.   The "buffered" strategy is now used in all
cases where :paramref:`_engine.Connection.execution_options.stream_results`
is set.

Added :meth:`.FilterResult.yield_per` so that result implementations
such as :class:`.MappingResult`, :class:`.ScalarResult` and
:class:`.AsyncResult` have access to this method.

Fixes: #8199

Change-Id: I6dde3cbe483a1bf81e945561b60f4b7d1c434750
2022-07-01 12:14:02 -04:00
Mike Bayer ad11c482e2 pep484 ORM / SQL result support
after some experimentation it seems mypy is more amenable
to the generic types being fully integrated rather than
having separate spin-off types.   so key structures
like Result, Row, Select become generic.  For DML
Insert, Update, Delete, these are spun into type-specific
subclasses ReturningInsert, ReturningUpdate, ReturningDelete,
which is fine since the "row-ness" of these constructs
doesn't happen until returning() is called in any case.

a Tuple based model is then integrated so that these
objects can carry along information about their return
types.  Overloads at the .execute() level carry through
the Tuple from the invoked object to the result.

To suit the issue of AliasedClass generating attributes
that are dynamic, experimented with a custom subclass
AsAliased, but then just settled on having aliased()
lie to the type checker and return `Type[_O]`, essentially.
will need some type-related accessors for with_polymorphic()
also.

Additionally, identified an issue in Update when used
"mysql style" against a join(), it basically doesn't work
if asked to UPDATE two tables on the same column name.
added an error message to the specific condition where
it happens with a very non-specific error message that we
hit a thing we can't do right now, suggest multi-table
update as a possible cause.

Change-Id: I5eff7eefe1d6166ee74160b2785c5e6a81fa8b95
2022-04-27 14:46:36 -04:00
Mike Bayer a4bb502cf9 pep-484 for engine
All modules in sqlalchemy.engine are strictly
typed with the exception of cursor, default, and
reflection.  cursor and default pass with non-strict
typing, reflection is waiting on the multi-reflection
refactor.

Behavioral changes:

* create_connect_args() methods return a tuple of list,
  dict, rather than a list of list, dict
* removed allow_chars parameter from
  pyodbc connector ._get_server_version_info()
  method
* the parameter list passed to do_executemany is now
  a list in all cases. previously, this was being run
  through dialect.execute_sequence_format, which
  defaults to tuple and was only intended for individual
  tuple params.
* broke up dialect.dbapi into dialect.import_dbapi
  class method and dialect.dbapi module object.  added
  a deprecation path for legacy dialects.  it's not
  really feasible to type a single attr as a classmethod
  vs. module type.  The "type_compiler" attribute also
  has this problem with greater ability to work around,
  left that one for now.
* lots of constants changing to be Enum, so that we can
  type them.  for fixed tuple-position constants in
  cursor.py / compiler.py (which are used to avoid the
  speed overhead of namedtuple), using Literal[value]
  which seems to work well
* some tightening up in Row regarding __getitem__, which
  we can do since we are on full 2.0 style result use
* altered the set_connection_execution_options and
  set_engine_execution_options event flows so that the
  dictionary of options may be mutated within the event
  hook, where it will then take effect as the actual
  options used.  Previously, changing the dict would
  be silently ignored which seems counter-intuitive
  and not very useful.
* A lot of DefaultDialect/DefaultExecutionContext
  methods and attributes, including underscored ones, move
  to interfaces.  This is not fully ideal as it means
  the Dialect/ExecutionContext interfaces aren't publicly
  subclassable directly, but their current purpose
  is more of documentation for dialect authors who should
  (and certainly are) still be subclassing the DefaultXYZ
  versions in all cases

Overall, Result was the most extremely difficult class
hierarchy to type here as this hierarchy passes through
largely amorphous "row" datatypes throughout, which
can in fact by all kinds of different things, like
raw DBAPI rows, or Row objects, or "scalar"/Any, but
at the same time these types have meaning so I tried still
maintaining some level of semantic markings for these,
it highlights how complex Result is now, as it's trying
to be extremely efficient and inlined while also being
very open-ended and extensible.

Change-Id: I98b75c0c09eab5355fc7a33ba41dd9874274f12a
2022-03-01 09:09:02 -05:00
Mike Bayer f113e97921 implement correct errors for Row immutability
Corrected the error message for the ``AttributeError`` that's raised when
attempting to write to an attribute on the :class:`_result.Row` class,
which is immutable. The previous message claimed the column didn't exist
which is misleading.

Fixes: #7432
Change-Id: If0e2cbd3f763dca6c99a18aa42252c69f1207d59
2021-12-09 14:23:42 -05:00
Mike Bayer 22deafe152 Warn when caching is disabled / document
This patch adds new warnings for all elements that
don't indicate their caching behavior, including user-defined
ClauseElement subclasses and third party dialects.
it additionally adds new documentation to discuss an apparent
performance degradation in 1.4 when caching is disabled as a
result in the significant expense incurred by ORM
lazy loaders, which in 1.3 used BakedQuery so were actually
cached.

As a result of adding the warnings, a fair degree of
lesser used SQL expression objects identified that they did not
define caching behavior so would have been producing
``[no key]``, including PostgreSQL constructs ``hstore``
and ``array``.  These have been amended to use inherit
cache where appropriate.  "on conflict" constructs in
PostgreSQL, MySQL, SQLite still explicitly don't generate
a cache key at this time.

The change also adds a test for all constructs via
assert_compile() to assert they will not generate cache
warnings.

Fixes: #7394
Change-Id: I85958affbb99bfad0f5efa21bc8f2a95e7e46981
2021-12-06 18:27:19 -05:00
Mike Bayer 9c5dfddfbd "graceful fetch" test should....clean up gracefully!
this test was relying on gc to close out the connection.
this would lead to problems with aiosqlite as we invalidate
async connetions that aren't gracefully closed, and this test
suite was create tables per suite, so we'd get into a spot where
a new sqlite memory connection without the tables would get set up.

would only occur for full test run + -n2 + C extensions + python 3.7,
but we assume that is all related to just getting gc to trigger
or not trigger at exactly the right moment in this situation.

confirmed if we add a gc.collect() to the test without explcitly
closing out the conenction, the connection is gc'ed and detached,
and we get the error reproduced on the subsequent test.

Change-Id: Icc9d4bc703f0842c27600f532f34bc4c7d3baf21
2021-11-26 18:49:34 -05:00
Federico Caselli 31acba8ff7 Clean up most py3k compat
Change-Id: I8172fdcc3103ff92aa049827728484c8779af6b7
2021-11-24 22:51:27 -05:00
Federico Caselli 0b95f0055b Remove object in class definition
References: #4600
Change-Id: I2a62ddfe00bc562720f0eae700a497495d7a987a
2021-11-22 15:03:17 +00:00
mike bayer 201c00bc08 Merge "fully implement future engine and remove legacy" into main 2021-11-07 21:19:45 +00:00
Mike Bayer d050193daa fully implement future engine and remove legacy
The major action here is to lift and move future.Connection
and future.Engine fully into sqlalchemy.engine.base.   This
removes lots of engine concepts, including:

* autocommit
* Connection running without a transaction, autobegin
  is now present in all cases
* most "autorollback" is obsolete
* Core-level subtransactions (i.e. MarkerTransaction)
* "branched" connections, copies of connections
* execution_options() returns self, not a new connection
* old argument formats, distill_params(), simplifies calling
  scheme between engine methods
* before/after_execute() events (oriented towards compiled constructs)
  don't emit for exec_driver_sql().  before/after_cursor_execute()
  is still included for this
* old helper methods superseded by context managers, connection.transaction(),
  engine.transaction() engine.run_callable()
* ancient engine-level reflection methods has_table(), table_names()
* sqlalchemy.testing.engines.proxying_engine

References: #7257

Change-Id: Ib20ed816642d873b84221378a9ec34480e01e82c
2021-11-07 14:30:35 -05:00
Mike Bayer 0c44a1e77c use tuple expansion if type._is_tuple, test for Sequence if no type
Fixed regression where the row objects returned for ORM queries, which are
now the normal :class:`_sql.Row` objects, would not be interpreted by the
:meth:`_sql.ColumnOperators.in_` operator as tuple values to be broken out
into individual bound parameters, and would instead pass them as single
values to the driver leading to failures. The change to the "expanding IN"
system now accommodates for the expression already being of type
:class:`.TupleType` and treats values accordingly if so. In the uncommon
case of using "tuple-in" with an untyped statement such as a textual
statement with no typing information, a tuple value is detected for values
that implement ``collections.abc.Sequence``, but that are not ``str`` or
``bytes``, as always when testing for ``Sequence``.

Added :class:`.TupleType` to the top level ``sqlalchemy`` import namespace.

Fixes: #7292
Change-Id: I8286387e3b3c3752b3bd4ae3560d4f31172acc22
2021-11-05 11:55:14 -04:00
mike bayer 37bc1285c5 Merge "ensure soft_close occurs for fetchmany with server side cursor" into main 2021-11-02 21:42:05 +00:00
Mike Bayer 33824a9c06 ensure soft_close occurs for fetchmany with server side cursor
Fixed regression where the :meth:`_engine.CursorResult.fetchmany` method
would fail to autoclose a server-side cursor (i.e. when ``stream_results``
or ``yield_per`` is in use, either Core or ORM oriented results) when the
results were fully exhausted.

All :class:`_result.Result` objects will now consistently raise
:class:`_exc.ResourceClosedError` if they are used after a hard close,
which includes the "hard close" that occurs after calling "single row or
value" methods like :meth:`_result.Result.first` and
:meth:`_result.Result.scalar`. This was already the behavior of the most
common class of result objects returned for Core statement executions, i.e.
those based on :class:`_engine.CursorResult`, so this behavior is not new.
However, the change has been extended to properly accommodate for the ORM
"filtering" result objects returned when using 2.0 style ORM queries,
which would previously behave in "soft closed" style of returning empty
results, or wouldn't actually "soft close" at all and would continue
yielding from the underlying cursor.

As part of this change, also added :meth:`_result.Result.close` to the base
:class:`_result.Result` class and implemented it for the filtered result
implementations that are used by the ORM, so that it is possible to call
the :meth:`_engine.CursorResult.close` method on the underlying
:class:`_engine.CursorResult` when the the ``yield_per`` execution option
is in use to close a server side cursor before remaining ORM results have
been fetched. This was again already available for Core result sets but the
change makes it available for 2.0 style ORM results as well.

Fixes: #7274
Change-Id: Id4acdfedbcab891582a7f8edd2e2e7d20d868e53
2021-11-02 16:31:12 -04:00
Federico Caselli 36e7aebd8d First round of removal of python 2
References: #4600
Change-Id: I61e35bc93fe95610ae75b31c18a3282558cd4ffe
2021-11-01 15:11:25 -04:00
mike bayer f5956e13d5 Merge "2.0 removals: LegacyRow, connectionless execution, close_with_result" into main 2021-10-31 20:48:33 +00:00
Mike Bayer aa026c302c 2.0 removals: LegacyRow, connectionless execution, close_with_result
in order to remove LegacyRow / LegacyResult, we have
to also lose close_with_result, which connectionless
execution relies upon.

also includes a new profiles.txt file that's all against
py310, as that's what CI is on now.  some result counts
changed by one function call which was enough to fail the
low-count result tests.

Replaces Connectable as the common interface between
Connection and Engine with EngineEventsTarget.  Engine
is no longer Connectable.  Connection and MockConnection
still are.

References: #7257
Change-Id: Iad5eba0313836d347e65490349a22b061356896a
2021-10-31 15:37:08 -04:00
Federico Caselli ed78e679ea Remove deprecated dialects and drivers
Fixes: #7258
Change-Id: I3577f665eca04f2632b69bcb090f0a4ec9271db9
2021-10-31 12:31:56 -04:00
Mike Bayer b7226379ac fixes for usage of the null() and similar constants
Adjusted the "column disambiguation" logic that's new in 1.4, where the
same expression repeated gets an "extra anonymous" label, so that the logic
more aggressively deduplicates those labels when the repeated element
is the same Python expression object each time, as occurs in cases like
when using "singleton" values like :func:`_sql.null`.  This is based on
the observation that at least some databases (e.g. MySQL, but not SQLite)
will raise an error if the same label is repeated inside of a subquery.

Related to 🎫`7153`, fixed an issue where result column lookups
would fail for "adapted" SELECT statements that selected for
"constant" value expressions most typically the NULL expression,
as would occur in such places as joined eager loading in conjunction
with limit/offset.  This was overall a regression due to issue
🎫`6259` which removed all "adaption" for constants like NULL,
"true", and "false", but this broke the case where the same adaption
logic were used to match the constant to a labeled expression referring
to the constant in a subquery.

Fixes: #7153
Fixes: #7154
Change-Id: I43823343721b9e70524ea3f5e8f39dd543a3e92b
2021-10-08 17:09:33 +00:00
Gord Thompson c2ea2b7308 Modernize tests - legacy_select
Change-Id: I04057cc3d3f93de60b02999803e2ba6a23cdf68d
2021-07-21 16:14:43 -04:00
mike bayer 673ca806b3 Merge "labeling refactor" 2021-07-13 14:25:13 +00:00
Mike Bayer 707e5d70fc labeling refactor
To service #6718 and #6710, the system by which columns are
given labels in a SELECT statement as well as the system that
gives them keys in a .c or .selected_columns collection have
been refactored to provide a single source of truth for
both, in constrast to the previous approach that included
similar logic repeated in slightly different ways.

Main ideas:

1. ColumnElement attributes ._label, ._anon_label, ._key_label
   are renamed to include the letters "tq", meaning
   "table-qualified" - these labels are only used when rendering
   a SELECT that has LABEL_STYLE_TABLENAME_PLUS_COL for its
   label style; as this label style is primarily legacy, the
   "tq" names should be isolated so that in a 2.0 style application
   these aren't being used at all

2. The means by which the "labels" and "proxy keys" for the elements
   of a SELECT has been centralized to a single source of truth;
   previously, the three of _generate_columns_plus_names,
   _generate_fromclause_column_proxies, and _column_naming_convention
   all had duplicated rules between them, as well as that there
   were a little bit of labeling rules in compiler._label_select_column
   as well; by this we mean that the various "anon_label" "anon_key"
   methods on ColumnElement were called by all four of these methods,
   where there were many cases where it was necessary that one method
   comes up with the same answer as another of the methods.  This
   has all been centralized into _generate_columns_plus_names
   for all the names except the "proxy key", which is generated
   by _column_naming_convention.

3. compiler._label_select_column has been rewritten to both not make
   any naming decisions nor any "proxy key" decisions, only whether
   to label or not to label; the _generate_columns_plus_names method
   gives it the information, where the proxy keys come from
   _column_naming_convention; previously, these proxy keys were matched
   based on restatement of similar (but not really the same) logic in
   two places.   The heuristics of "whether to label or not to label"
   are also reorganized to be much easier to read and understand.

4. a new method compiler._label_returning_column is added for dialects
   to use in their "generate returning columns" methods.   A
   github search reveals a small number of third party dialects also
   doing this using the prior _label_select_column method so we
   try to make sure _label_select_column continues to work the
   exact same way for that specific use case; for the "SELECT" use
   case it now needs

5. After some attempts to do it different ways, for the case where
   _proxy_key is giving us some kind of anon label, we are hard
   changing it to "_no_label" right now, as there's not currently
   a way to fully match anonymized labels from stmt.c or
   stmt.selected_columns to what will be in the result map.  The
   idea of "_no_label" is to encourage the user to use label('name')
   for columns they want to be able to target by string name that
   don't have a natural name.

Change-Id: I7a92a66f3a7e459ccf32587ac0a3c306650daf11
2021-07-12 18:50:29 -04:00
Gord Thompson 4ff4760fad Modernize tests - select(whereclause)
Change-Id: I306cfbea9920b35100e3087dcc21d7ffa6c39c55
2021-07-04 15:56:40 -06:00
Mike Bayer cdd041ea60 consider "*" col as textual ordered
Fixed old issue where a :func:`_sql.select()` made against the token "*",
which then yielded exactly one column, would fail to correctly organize the
``cursor.description`` column name into the keys of the result object.

Fixes: #6665
Change-Id: Ie8c00f62998972ad4a19a750d2642d00fde006f6
2021-06-23 09:49:11 -04:00
Mike Bayer 6967b45020 don't cache TypeDecorator by default
The :class:`.TypeDecorator` class will now emit a warning when used in SQL
compilation with caching unless the ``.cache_ok`` flag is set to ``True``
or ``False``. ``.cache_ok`` indicates that all the parameters passed to the
object are safe to be used as a cache key, ``False`` means they are not.

Fixes: #6436
Change-Id: Ib1bb7dc4b124e38521d615c2e2e691e4915594fb
2021-05-06 13:57:43 -04:00
Mike Bayer d6ec248fa7 Establish deprecation path for CursorResult.keys()
Established a deprecation path for calling upon the
:meth:`_cursor.CursorResult.keys` method for a statement that returns no
rows to provide support for legacy patterns used by the "records" package
as well as any other non-migrated applications. Previously, this would
raise :class:`.ResourceClosedException` unconditionally in the same way as
it does when attempting to fetch rows. While this is the correct behavior
going forward, the :class:`_cursor.LegacyCursorResult` object will now in
this case return an empty list for ``.keys()`` as it did in 1.3, while also
emitting a 2.0 deprecation warning. The :class:`_cursor.CursorResult`, used
when using a 2.0-style "future" engine, will continue to raise as it does
now.

Fixes: #6427
Change-Id: I4148f28c88039e4141deeab28b1a5994e6d6e098
2021-05-04 13:49:43 -04:00
Mike Bayer dca3a43de6 Fix LegacyRow/Row index access
Fixed up the behavior of the :class:`_result.Row` object when dictionary
access is used upon it, meaning converting to a dict via ``dict(row)`` or
accessing members using strings or other objects i.e. ``row["some_key"]``
works as it would with a dictionary, rather than raising ``TypeError`` as
would be the case with a tuple, whether or not the C extensions are in
place. This was originally supposed to emit a 2.0 deprecation warning for
the "non-future" case using :class:`_result.LegacyRow`, and was to raise
``TypeError`` for the "future" :class:`_result.Row` class. However, the C
version of :class:`_result.Row` was failing to raise this ``TypeError``,
and to complicate matters, the :meth:`_orm.Session.execute` method now
returns :class:`_result.Row` in all cases to maintain consistency with the
ORM result case, so users who didn't have C extensions installed would
see different behavior in this one case for existing pre-1.4 style
code.

Therefore, in order to soften the overall upgrade scheme as most users have
not been exposed to the more strict behavior of :class:`_result.Row` up
through 1.4.6, :class:`_result.LegacyRow` and :class:`_result.Row` both
provide for string-key access as well as support for ``dict(row)``, in all
cases emitting the 2.0 deprecation warning when ``SQLALCHEMY_WARN_20`` is
enabled. The :class:`_result.Row` object still uses tuple-like behavior for
``__contains__``, which is probably the only noticeable behavioral change
compared to :class:`_result.LegacyRow`, other than the removal of
dictionary-style methods ``values()`` and ``items()``.

Also remove filters for result set warnings.

callcounts updated for 2.7/ 3.9, am pushing jenkins to use python 3.9
now

Fixes: #6218
Change-Id: Ia69b974f3dbc46943c57423f57ec82323c8ae63b
2021-04-08 16:06:41 -04:00
Federico Caselli 3df6a3f1fb Repair exception handling in CursorResult
Fixes: #6138
Change-Id: I794a3da688fd8577fb06770ef02bf827a5c55397
2021-03-30 19:13:58 -04:00